Scribble at 2022-11-18 11:44:49 Last modified: 2022-11-18 12:01:57

添付画像

パスを指定した場合 — 絶対パス (Windows ならドライブレターあるいは \ で始まるパス、Unix/Linux 系なら / で始まるパス) あるいはカレントディレクトリからの相対パス (. あるいは .. で始まるパス) のどちらでも — は include_path は無視されます。たとえば ../ ではじまるファイル名を指定した場合は、 親ディレクトリからそのファイルを探します。

PHP: include - Manual

PHP でコードを書いて20年近くになるんだけど、いまだにたびたび困惑させられるのが、絶対にあるはずのファイルがないという "No such file or directory" だ。もちろん、Dropbox のデスクトップ・クライアントのように、コンピュータの世界ではハンドリング対象のデータとして運用する以外にコーディングで使うべきではない筈の、東アジアの辺境国家でしか使われていない「日本語」なんていう言語の文字を使うフォルダ名を Dropbox のホーム・フォルダとして強制されるクズみたいなアプリケーションを使ってると起きやすいとは言うが、決してそれだけが原因ではない。ちなみに、子供に英語に慣れるための訓練をさせたいと思うなら、フォルダ名を全て英語で作らせるのがいい。素早くファイルを探すために英語の単語を無理やりにでもシークしなくてはいけないという習慣をつけると、自然に慣れるものである。各国の軍隊やハードな教え方をする英会話教室の合宿などで、目的の言語でしか生活できない環境に置くというのは、そういう効用があるからだ。生きるために必要だという切実な事情もなく、ドラマを字幕なしで観たいとか「国際人」とか、そういう下らない理由では外国語なんて永久に上達しない。

それはそうと、この一つの原因として知られているようで知られていない(よって、僕もよく忘れる)のが、require, require_once といった制御構造(ちなみに、これらは関数ではないので、require() などと関数のように書くのは混乱するため、実は好ましくない)の仕様である。そして、この仕様がよく知られていない理由の一つとして、僕は PHP の公式マニュアルが文章として酷過ぎるからではないかと言いたい。

上記に引用したのが、require, include などの制御構造でファイルの所在を指定するための仕様を述べた個所だ。PHP の公式マニュアルの作成なり翻訳のルールは知らないし興味もないが、ちょっと上記の翻訳はどうなのかと思わざるを得ない。

原文:"If a path is defined — whether absolute (starting with a drive letter or \ on Windows, or / on Unix/Linux systems) or relative to the current directory (starting with . or ..) — the include_path will be ignored altogether. For example, if a filename begins with ../, the parser will look in the parent directory to find the requested file."

翻訳:パスが指定されたとき、それが絶対パス(ドライブ文字、あるいは Windows なら "\" で始まるパス、もしくは UNIX/Linux なら "/" で始まるパス)であろうと、あるいはコードが実行されるカレント・ディレクトリからの相対パス( "." もしくは ".." で始まるパス)であろうと、include_path で指定されたパスは全て無視されます。たとえば、"../" で始まるファイル名がパスとして指定されると、PHP のパーサはコードの親ディレクトリを基準に目的のファイルを探します。

つまり、公式の翻訳は "the include_path will be ignored altogether" を正しく訳していないし、多くの日本語ではダッシュなどを用いて囲んだ挿入句は、しばしばダッシュが三点リーダの代わりに(英語ならコロンのように)単独で使われることを理解していない人が翻訳している。上記のような長文をダッシュで囲んで但し書きにすることは、日本語では好ましくないのだ。但し書きであることを読んでいる人へはっきりと知らせるには、やはり日本語では括弧を使う方がよいし、可能なら長文になっても但し書きを必要としない文章を書くべきだし、長すぎるなら注釈にして追い出した方がいい場合もある。

しかし、require_once './_tpl/header.html'; などというコードを書いてもエラーとなる。この記述は仕様としても間違っていない。なのに、この書き方だと自宅の PHP 8.1 では動いても会社の PHP 7.4(まだアップデートしてない)ではエラーになる。

他によくあるミスは、php.ini で allow_url_include が有効になっていない場合だが、これは僕らのような情報セキュリティの実務家でも、滅多に無効にはしない(大半のフレームワークや標準的なプログラミングでは、include や require を使わずに80番ポートでアクセスできるディレクトリにあるコード、つまりは UA からリクエストされた PHP ファイルだけで全ての処理を実行してレスポンスする方が危険だからだ)。そして、httpd のログを見ると、ごく普通の favicon.ico ファイルについて「(OS 1920)ファイルにアクセスできません」というエラーが出ている。アクセスしているディレクトリは Dropbox のクライアントが管理しているため、いったんクライアントの同期を切ってみたが(クラウド・ストレージのクライアント・ソフトがファイルをロックしてしまう場合がある)、それでもエラーはなくならない。同じく Dropbox の管理下にあって、同じように require_once で相対パスを使ったファイルの読み込みをしている MD や PHILSCI.INFO のテスト・サイトは正しく表示されるが、仕事などで作成した virtual host ではエラーが出る。もちろん、virtual host としての設定も、ほぼ root directory の設定くらいしか違いがないにも関わらずだ。

しかし、特にクラウド・ストレージを使っていると特有の事情でエラーが起きることもある。僕がしばしば忘れてしまうのは、Dropbox の「スマートシンク」という、実体がローカルにない保存方法を使っていることだ。もちろん、ローカル・ストレージの容量を節約するために便利な機能ではあるが、エクスプローラやファイル・マネージャで見えているファイル名やフォルダ名がエイリアスでしかないという事実を忘れてしまい、「あるのにアクセスできないとは何事か」と思ってしまったりする。今回のエラーも、これが原因であった。もちろん、こういう場合は(スマートシンクという表現は誤解を招くらしく、もうあまり使われていないようだが)ローカルにもファイルを同期するように設定を変更すればいい。

  1. もっと新しいノート <<
  2. >> もっと古いノート

冒頭に戻る


※ 以下の SNS 共有ボタンは JavaScript を使っておらず、ボタンを押すまでは SNS サイトと全く通信しません。

Twitter Facebook