ホームページ  >  記事  >  php教程  >  PHP における一般的で紛らわしい技術的なポイントに関するベスト プログラミング プラクティス

PHP における一般的で紛らわしい技術的なポイントに関するベスト プログラミング プラクティス

WBOY
WBOYオリジナル
2016-06-21 08:49:401677ブラウズ

最新の改善とメンテナンス

この文書は 2013 年 3 月 8 日に最後にレビューされました。最終変更は 2013 年 3 月 8 日でした。

これは私、Alex Cabal によって管理されています。私は長い間 PHP コードを書いてきました。現在は、本格的なライター向けのオンライン執筆グループである Scribophile、フリーランサー向けのシンプルなオンライン執筆フォルダーである Writerfolio、イラスト出版物である Standard Ebooks、パブリック ドメインの電子書籍である Standard Ebooks を運営しています。デジタル著作権のない書籍。 時々、興味のあるプロジェクトやクライアントを自由に追求することがあります。

私が何かお手伝いできると思われる場合、またはこの記事について提案や修正がある場合は、私に連絡してください。

はじめに

PHP は、何年にもわたって自分の中でひねったり、曲げたり、伸ばしたり、叩いたりする必要がある複雑な言語です。それは矛盾しており、時にはバグに満ちています。各バージョンには独自の機能、欠陥、癖があり、どのバージョンにどの問題があるかを追跡するのは困難な場合があります。それが時として大きな怒りを生む理由を想像するのは難しくありません。

それにもかかわらず、それは今日ウェブ上で最も人気のある言語です。長い歴史があるため、パスワード ハッシュ (1 回限りの暗号化) やデータベース アクセスなどの基本的なことを行う方法に関するチュートリアルが数多く見つかります。問題は、5 つのチュートリアルから、何かを行うための 5 つのまったく異なる方法が見つかる可能性が高いことです。どの方法が「正しい」方法ですか?他の方法に欠陥や予期せぬ問題はありますか?それを理解するのは非常に難しく、正しい答えを見つけようとしてウェブ中をクリックすることになります。

これが、新人の PHP プログラマーが醜い、時代遅れ、または安全でないコードで批判される理由の 1 つです。最初の Google 検索結果が 5 年前のメソッドを教える 4 年前の記事だった場合、彼らはその状況を変えずにはいられません。

この記事はまさにそれを試みようとしています。これは、PHP でよくある紛らわしい問題に対処するためのベスト プラクティスと考えられる一連の基本的な操作ヒントをまとめることを目的としています。 PHP に複数の紛らわしいメソッドを含む低レベルのタスクがあった場合、それはここに属します。

それは何ですか

これは、PHP プログラマーが遭遇する可能性のある一般的な低レベルのタスクに直面した場合に最適なアプローチを示す推奨ガイドです。PHP には多くの選択肢があるため、これらのタスクを理解するのは容易ではありません。例: データベースへの接続は、考えられる多くの PHP ソリューションで一般的なタスクですが、すべてが適切であるわけではありません。そのため、この問題はこの記事に含まれています。

これは一連の短いガイド付きソリューションです。基本的な構成でサンプルを実行するための措置を講じる必要があります。また、自分に適したものを見つけるために独自の調査を行う必要があります。

これは、私たちが理解している PHP の最先端技術を指します。ただし、これは、古いバージョンの PHP を使用している場合、これらのソリューションを実装するために必要な機能の一部が備わっていない可能性があることも意味します。

これは生きたドキュメントであり、PHP が進化し続けるのに合わせて更新し続けるように努めます。

それは何でしょうか?

この記事は PHP チュートリアルではありません。基本と文法は別の場所で学ぶ必要があります。

これは、Cookie ストレージ、キャッシュ、コーディング スタイル、ドキュメントなどの一般的な Web アプリケーションの問題についてのガイドではありません。

これはセキュリティウィザードではありません。セキュリティ関連の問題に関しては、PHP アプリケーションを強化する方法について独自に調査する必要があります。特に、ここで挙げた提案は実装する前に注意深く検討する必要があります。コードに対する責任はあなたにあります。

特定のコーディング スタイル、パターン、フレームワークを推奨するものではありません。

ユーザー登録やシステムへのログインなどの高レベルのタスクを実行する方法に関する特定のアプローチを支持するものではありません。 PHP の長い歴史は混乱を招き、または不明瞭になる可能性があるため、この記事は厳密に低レベルのタスクを対象としています。

それは究極の解決策ではありませんし、唯一の解決策でもありません。以下で説明する方法の中には、実際の状況に最適ではないものもあります。また、同じ目的を達成できるさまざまな方法が多数あります。特に、高負荷の Web アプリケーションでは、これらの問題に対するよりステルスなソリューションの恩恵を受ける可能性があります。

使用している PHP のバージョンはどれですか?

Suhosin パッチを適用した PHP 5.3.10-1ubuntu3.6、Ubuntu 12.04 LTS にインストール。

PHP は、インターネットの世界で 100 年前のカメのようなものです。その殻には、豊かで不可解で粗野な歴史が刻まれています。共有ホスティング環境では、その構成によってできることが制限される場合があります。

健全性を保つには、PHP の 1 つのバージョンだけに焦点を当てる必要があります。 2013年4月30日現在のバージョンは、Suhosinパッチを適用したPHP5.3.10-1ubuntu3.6です。 apt-get を使用して Ubuntu 12.04 LTS サーバーから PHP をインストールする場合、これが取得されるバージョンです。言い換えれば、多くの人がデフォルトですでに賢く使用しているということです。

この記事の解決策は、別のバージョンまたは古いバージョンの PHP でも機能する場合があります。この場合、これらの古いバージョンの微妙なバグやセキュリティ上の問題の影響を調査するのはあなた次第です。

パスワードを保存

phpass ライブラリを使用して、比較のためにパスワードのハッシュを計算します。

phpass 0.3でテスト済み。

ハッシュは、ユーザーのパスワードをデータベースに保存する前に保護する標準的な方法です。 MD5 や SHA1 などの一般的なハッシュ アルゴリズムの多くは、ハッカーがこれらのハッシュ アルゴリズムを使用するとパスワードを簡単に解読できるため、パスワードの保存には安全ではありません。

パスワードをハッシュする最も安全な方法は、bcrypt アルゴリズムを使用することです。オープンソースの phpass ライブラリは、この機能を使いやすいクラスで提供します。

例:

01

02 // 包含phpass库

03 require_once('phpass-0.3/PasswordHash.php');

04

05 // 初始化散列器为不可移植(这样更安全)

06 $hasher = new PasswordHash(8, false);

07

08 // 计算密码哈希值。$hashedPassword 将会是一长为60个字符的字符串.

09 $hashedPassword = $hasher->HashPassword('my super cool password');

10  

11 // 你现在可以安全地保存$hashedPassword到数据库中!

12  

13 // 通过比较用户输入内容(产生的哈希值)和我们之前计算出的哈希值,来判断用户是否输入了正确的密码

14 $hasher->CheckPassword('the wrong password', $hashedPassword); // 返回假

15  

16 $hasher->CheckPassword('my super cool password', $hashedPassword); // 返回真

17 ?>

トラップ

  • 多くの情報源では、ハッシュを計算する前にパスワードを調整することを推奨しています。これは良いアイデアです。phpass はすでに HashPassword() 関数のコードの一部を使用して、パスワードにスパイスを加えています。 つまり、これを自分で行う必要がなくなりました。

さらに読む

  • パスパス
  • md5 または sha でパスワードをハッシュすることが安全でない理由
  • パスワードを安全に保存する方法

MySQL データベースに接続してクエリを実行

PDO とその定義済みステートメント機能を使用します。

PHP で MySQL データベースに接続するには、さまざまな方法があります。 PDO (PHP Data Objects) は、その中で最新かつ最も堅牢です。 PDO は、さまざまな種類のデータベースに対して一貫したインターフェイスを使用し、オブジェクト指向のアプローチを採用し、新しいデータベースによって提供されるより多くの機能をサポートします。

SQL インジェクション攻撃を防ぐには、PDO プリペアド ステートメント機能を使用する必要があります。 bindValue() 関数を使用して、SQL が一次 SQL インジェクション攻撃から安全であることを確認します (ただし、これは 100% 確実というわけではありません。詳細については「参考文献」を参照してください)。以前は、これはいくつかの「魔法の引用」関数を複雑に組み合わせることによってのみ実現できました。 PDO を使用すると、こうした厄介な問題はすべて不要になります。

01

02 try{

03 // Create a new connection.

04 // You'll probably want to replace hostname with localhost in the first parameter.

05 // The PDO options we pass do the following:

06 // PDO::ATTR_ERRMODE enables exceptions for errors. This is optional but can be handy.

07 // PDO::ATTR_PERSISTENT disables persistent connections, which can cause concurrency issues in certain cases. See "Gotchas".

08 // PDO::MYSQL_ATTR_INIT_COMMAND alerts the connection that we'll be passing UTF-8 data. This may not be required depending on your configuration, but it'll save you headaches down the road if you're trying to store Unicode strings in your database. See "Gotchas".

09 $link = new PDO( 'mysql:host=your-hostname;dbname=your-db',

10 'your-username',

11 'your-password',

12 array(

13 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

14                             PDO::ATTR_PERSISTENT => false,

15                             PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'

16                         )

17                     );

18  

19     $handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');

20  

21     // PHP bug: if you don't specify PDO::PARAM_INT, PDO may enclose the argument in quotes.  This can mess up some MySQL queries that don't expect integers to be quoted.

22     // See: https://bugs.php.net/bug.php?id=44639

23     // If you're not sure whether the value you're passing is an integer, use the is_int() function.

24     $handle->bindValue(1, 100, PDO::PARAM_INT);

25     $handle->bindValue(2, 'Bilbo Baggins');

26     $handle->bindValue(3, 5, PDO::PARAM_INT);

27  

28     $handle->execute();

29  

30     // Using the fetchAll() method might be too resource-heavy if you're selecting a truly massive amount of rows.

31     // If that's the case, you can use the fetch() method and loop through each result row one by one.

32     // You can also return arrays and other things instead of objects.  See the PDO documentation for details.

33     $result = $handle->fetchAll(PDO::FETCH_OBJ);

34  

35     foreach($result as $row){

36         print($row->Username);

37     }

38 }

39 catch(PDOException $ex){

40     print($ex->getMessage());

41 }

42 ?>

トラップ

  • 整数変数をバインドする場合、PDO::PARAM_INT パラメーターを渡さないと、PDO がデータを引用符で囲む可能性があります。これにより、特定の MySQL クエリが破損する可能性があります。このバグレポートを参照してください。

  • 最初のクエリとして「set names utf8mb4」を使用しないと、構成によっては Unicode データがデータベースに誤って保存される可能性があります。 Unicode でエンコードされたデータに問題がないと確信できる場合は、これを無視してかまいません。

  • 永続的な接続を有効にすると、同時実行に関連した奇妙な問題が発生する可能性があります。これは PHP の問題ではなく、アプリケーション レベルの問題です。結果を注意深く考慮する限り、永続的な接続は通常は安全です。 Stack Overflow でこの質問を確認してください。

  • `set names utf8mb4` を使用する場合でも、実際のデータベース テーブルが utf8mb4 文字セットを使用していることを確認する必要があります。

  • 複数の SQL ステートメントを 1 回の use() 呼び出しで実行できます。セミコロンを使用してステートメントを区切るだけですが、このバグはこのドキュメントが書かれている PHP バージョンでは修正されていないことに注意してください。

さらに読む

  • PHP マニュアル: PDO
  • データベースへのアクセスに PHP の PDO を使用する必要がある理由
  • スタック オーバーフロー: PHP PDO とプレーンな mysql_connect
  • スタック オーバーフロー: PDO プリペアド ステートメントは SQL インジェクションを防ぐのに十分ですか?
  • スタック オーバーフロー: MySQL で SET NAMES utf8 を使用しますか?

PHP タグ

を使用してください。

PHP コードのブロックを定義するには、、<% %> など、いくつかの方法があります。短いメソッドの方が入力は簡単ですが、すべての PHP サーバーで動作することが保証されているのは だけです。構成を制御できないサーバーに PHP プログラムをデプロイする予定がある場合は、常に を使用する必要があります。

PHP ランタイム環境の構成を制御する十分な権限がある場合は、短いタグを使用する方が自然に便利であることがわかります。ただし、 は実際には ASP スタイルであることに注意してください。

どちらを選択する場合でも、一貫性を保つようにしてください。

トラップ

    純粋な PHP ファイル (クラス定義のみを含むファイルなど) に末尾を含める場合はどうすればよいですか? > タグを付け、その後に改行を残さないようにしてください。 PHP パーサーは終了タグの後の改行を安全に「食べる」ことができますが、他の改行がブラウザーに出力される可能性があり、後で HTTP ヘッダーを出力するときに干渉が発生する可能性があるためです。
  • Web アプリケーションを作成するときは、終了タグ ?> タグと html の間に改行を入れないよう注意してください。正しい HTML を実現するには、 タグをファイルの最初の行にする必要があります。その前にスペースや改行があると無効になります。
さらに読む

  • スタック オーバーフロー: PHP の短いタグは使用できますか?

オートロードクラス

spl_autoload_register() を使用して、自動ロードする関数を登録します。

PHP には、まだロードされていないクラスを含むファイルを自動的にロードする方法がいくつか用意されています。古い方法は、__autoload() と呼ばれるマジック グローバル関数を使用する方法です。ただし、定義された __autoload() 関数は一度に 1 つしか使用できないため、__autoload() 関数も使用するライブラリを含めると競合が発生します。

この問題を解決する正しい方法は、自動ロード関数に一意の名前を付けて、それを spl_autoload_register() 関数に登録することです。この関数を使用すると、他のコードに含まれる __autoload() 関数をステップ実行しないように、複数の __autoload() 関数を定義できます。

例:

01

02 // 首先,定义你的自动载入的函数

03 function MyAutoload($className){

04 include_once($className . '.php');

05 }

06

07 // 然后注册它.

09

10 // 试试让它工作!

11 // 因为我们没包含一个定义有MyClass的文件,所以自动加载器会介入并包含MyClass.php.

12 // 对本例来说,假定在MyClass.php文件中定义了MyClass类.

13 $var = new MyClass();

14 ?>

さらに読む

  • PHP マニュアル: spl_autoload_register()
  • スタック オーバーフロー: 効率的な PHP の自動読み込みと命名戦略

パフォーマンスの観点から一重引用符と二重引用符を比較する

それは問題ではありません。

文字列を定義するときに一重引用符を使用するか二重引用符を使用するかについては、多くのことが書かれています。一重引用符で囲まれた文字列は解析されないため、文字列に入力した内容はそのまま表示されます。二重引用符で囲まれた文字列が解析され、その文字列内の PHP 変数が評価されます。また、エスケープ文字 (改行 n やタブ t など) についても、一重引用符と二重引用符の違いは同様です。

二重引用符で囲まれた文字列は実行時に解析されるため、理論上、可能であれば一重引用符を使用すると、PHP で一重引用符で囲まれた文字列をさらに解析する必要がなくなるため、パフォーマンスが向上します。これは、特定の規模のアプリケーションには当てはまりますが、一般的な実際のアプリケーションでは、効率の差は非常に小さいため、実際には問題になりません。したがって、一般的なアプリケーションでは、どちらを選択しても問題はありません。将来的には二重引用符に変更してください)。非常に高負荷のアプリケーションでは、多少の影響がある可能性があります。どの方法を使用するかはアプリケーションのニーズによって異なりますが、どの方法を選択しても一貫性を保つ必要があります。

さらに読む

  • PHP マニュアル: 文字列
  • PHP ベンチマーク (見積タイプまで下にスクロール)
  • スタック オーバーフロー: PHP では単一引用符と二重引用符にパフォーマンス上の利点がありますか?

define() と const

の比較

「可読性、クラス定数、マイクロ最適化」が重要でない場合は、define() を使用してください

従来、PHP では、define() 関数を使用して定数を定義していました。しかし、一部の意見によると、PHP には const キーワードを使用して定数を宣言する機能も追加されました。では、定数を定義するときはどれを使用すべきでしょうか?

答えは、これら 2 つの方法のわずかな違いにあります。

  1. define() は実行時に定数を定義し、const はコンパイル時に定数を定義します。これにより const は速度がわずかに向上しますが、大規模なソフトウェアを構築していない限り、心配する必要があるほどではありません。
  2. define() は定数をグローバル スコープに置きますが、定数名に名前空間を含めることもできます。これは、define() を使用してクラス定数を定義できないことを意味します。
  3. define() では定数名と定数値の両方で式を使用できますが、const ではどちらも使用できません。これにより、define() がより柔軟になります。
  4. define() は if() ブロック内で使用できますが、const は使用できません。

例:

01

02 // 来看看这两种方法如何处理名称空间

03 namespace MiddleEarthCreaturesDwarves;

04 const GIMLI_ID = 1;

05 define('MiddleEarthCreaturesElvesLEGOLAS_ID', 2);

06

07 echo(MiddleEarthCreaturesDwarvesGIMLI_ID); // 1

08 echo(MiddleEarthCreaturesElvesLEGOLAS_ID); // 2; 注意,对此常量,我们是用define()定义的,但也能识别空间。

09

10 // 现在让我们来声明一些值是移运算结果的常数来代表进入魔多的方式Mordor.

11 define('TRANSPORT_METHOD_SNEAKING', 1 << 0); // OK!

12 const TRANSPORT_METHOD_WALKING = 1 << 1; //编译错误! const 不允许使用表达式作为值

13

14 // 接下来, 条件常量。

15 define('HOBBITS_FRODO_ID', 1);

16

17 if($isGoingToMordor){

18 define('TRANSPORT_METHOD', TRANSPORT_METHOD_SNEAKING); // OK!

19 const PARTY_LEADER_ID = HOBBITS_FRODO_ID // 编译错误: const 不能用于 if 块中

20 }

21

22 // 最后, 类常量

23 class OneRing{

24 const MELTING_POINT_DEGREES = 1000000; // OK!

25 define('SHOW_ELVISH_DEGREES', 200); // 编译错误: 在类内不能使用define()

26 }

27 ?>

最終的にはdefine()の方が柔軟性が高いため、クラス定数が絶対に必要な場合を除き、問題を回避するのはあなたの選択です。 const を使用すると、より読みやすいコードが生成されますが、柔軟性が犠牲になります。

どちらを使用する場合でも、一貫性を保ってください。

さらに読む

  • スタック オーバーフロー:define() と const
  • PHP マニュアル: 定数
  • スタック オーバーフロー:define() と variable

PHP オペコード (バイトコード) のキャッシュ

APC を使用します。

PHP の標準インストール環境では、各 PHP スクリプトはオペコード (バイトコード) ファイルにコンパイルされ、アクセスされるたびに実行されます。まったく同じスクリプトを何度もコンパイルするのに時間を費やすと、大規模な Web サイトでは必ずパフォーマンスの問題が発生します。

解決策はオペコードのキャッシュです。オペコード キャッシュは、サーバーがスクリプトを何度もコンパイルする無駄な時間を費やす必要がないように、各スクリプトのコンパイル結果を記憶するシステムです。また、通常、スクリプトが変更されたことを検出して再コンパイルするのに十分な機能を備えているため、PHP ソース ファイルを更新するときに手動でキャッシュをクリアする必要がありません。

利用可能な PHP オペコード キャッシュ システムはいくつかありますが、注目に値するのは eaccelerator、xcache、APC であり、PHP プロジェクト チームによって正式にサポートされており、最もアクティブでインストールが簡単です。また、オプションで memcached のような永続的なキーと値のストアも提供します。これらの理由から、これを使用する必要があります。

APC をインストール

APC は、ターミナルで次のコマンドを実行することで Ubuntu 12.04 にインストールできます:

sudo apt-get install php-apc

追加の構成は必要ありません。

APC を永続的なキーと値のストアとして使用する

APC は、memcached のような機能も提供します。これはスクリプトにとっても明らかです。 memcached を使用する場合と比較した最大の利点は、APC が PHP カーネルに統合されているため、可動部分をサーバーに保存する必要がなく、PHP 開発者が積極的に取り組んでいることです。一方、APC は分散キャッシュではありません。この機能が必要な場合は、memcached を使用する必要があります。

01

02 // Store some values in the APC cache. We can optionally pass a time-to-live, but in this example the values will live forever until they're garbage-collected by APC.

03 apc_store('username-1532', 'Frodo Baggins');

04 apc_store('username-958', 'Aragorn');

05 apc_store('username-6389', 'Gandalf');

06

07 // After storing these values, any PHP script can access them, no matter when it's run!

08 $value = apc_fetch('username-958', $success);

09 if($success === true)

10 print($value); // Aragorn

11

12 $value = apc_fetch('username-1', $success); // $success will be set to boolean false, because this key doesn't exist.

13 if($success !== true) // Note the !==, this checks for true boolean false, not "falsey" values like 0 or empty string.

14 print('Key not found');

15

16 apc_delete('username-958'); // This key will no longer be available.

17 ?>

Gotchas = わかりました

  • PHP-FPM を使用しない場合 (たとえば、mod_php または mod_fastcgi を使用する場合)、各 PHP プロセスは、キーと値のストレージを含む独自の一意の APC インスタンスを持ちます。注意しないと、アプリケーション コードで同期の問題が発生する可能性があります。

さらに読む

  • PHP マニュアル: APC

PHP と Memcached

分散キャッシュが必要な場合は、Memcached クライアント ライブラリを使用します。または、APC を使用します。

キャッシュ システムにより、多くの場合、アプリのパフォーマンスが向上します。 Memcached は人気のある選択肢であり、PHP を含む多くの言語と互換性があります。

ただし、PHP スクリプトから Memcached サーバーにアクセスする場合は、Memcache と Memcached という 2 つの異なる、愚かな名前のクライアント ライブラリ オプションがあります。これらは異なるライブラリですが、名前はほぼ同じで、どちらも Memcached インスタンスにアクセスするために使用されます。

Memcached ライブラリが Memcached プロトコルを実装する最良の方法であることは事実によって証明されています。これには、Memcache ライブラリにはない便利な機能がいくつか含まれており、最も活発に開発されているようです。

ただし、一連の分散サーバーから Memcached インスタンスにアクセスする必要がない場合は、代わりに APC を使用してください。 APC は PHP プロジェクトによってサポートされており、Memcached に似た多くの機能を備えています。さらに驚くべきことに、PHP スクリプトのパフォーマンスを向上させるオペコード キャッシュがあることです。

Memached クライアント ライブラリをインストールします

Memcached サーバーをインストールした後、Memcached クライアント ライブラリをインストールする必要があります。このライブラリがないと、PHP スクリプトは Memcached サーバーと通信できません。

ターミナルで次のコマンドを実行して、Memcached クライアント ライブラリをインストールできます:

sudo apt-get install php5-memcached

代わりに APC を使用してください

Memcached の代替として APC を使用する方法の詳細については、オペコード キャッシュに関するエントリを参照してください。

さらに読む

  • PHP マニュアル: Memcached
  • PHP マニュアル: APC
  • スタック オーバーフロー: PHP での Memcache と Memcached の使用
  • スタック オーバーフロー: Memcached と APC、どちらを選択すべきですか?

PHP と正規表現

PCRE (preg_*) ファミリ関数の使用

PHP では、正規表現を使用する 2 つの異なる方法があります。PCRE (Perl 互換、preg_*) 関数と POSIX (POSIX 拡張、ereg_*) 関数です。

関数の各ファミリーは、わずかに異なるスタイルの正規表現を使用します。幸いなことに、POSIX 関数は PHP 5.3.0 から非推奨になりました。このため、新しいコードでは POSIX 関数を使用しないでください。これは常に Warrior PRCE 関数、つまり preg_* 関数です。

さらに読む

  • PHP マニュアル: PCRE
  • PHP 正規表現の入門

PHP サービスを提供するように Web サーバーを構成します

PHP-FPM の使用

PHP を提供するように Web サーバーを構成するには、いくつかの方法があります。従来の (そして悪い) 方法は、Apache の mod_php を使用することです。 Mod_php は PHP を Apache 自体にバインドしますが、Apache はこのモジュールの機能を管理するのに非常に不十分です。大量のトラフィックに遭遇すると、深刻なメモリ問題に悩まされることになります。

mod_fastcgi と mod_fcgid という 2 つの新しいオプションがすぐに人気になりました。どちらも一定数の PHP 実行プロセスを維持し、Apache はこれらのポートにリクエストを送信して PHP の実行を処理します。これらのライブラリはアクティブな PHP プロセスの数を制限するため、パフォーマンスに影響を与えることなくメモリ使用量が大幅に削減されます。

一部の賢い人々は、PHP で実際にうまく動作するように特別に設計された fastcgi の実装を作成し、それを PHP-FPM と呼びました。 PHP 5.3.0 より前は、インストールするために多くの困難を乗り越える必要がありましたが、幸いなことに、PHP 5.3.3 にはコアに PHP-FPM が含まれていたため、Ubuntu 12.04 へのインストールは非常に簡単でした。

次の例は Apache 2.2.22 用ですが、PHP-FPM は Nginx

などの他の Web サーバーでも使用できます。

PHP-FPM と Apache をインストールします

ターミナルで次のコマンドを実行して、PHP-FPM と Apache を Ubuntu 12.04 にインストールします:

sudo apt-get install apache2-mpm-worker libapache2-mod-fastcgi php5-fpm sudo a2enmod アクション エイリアス fastcgi

apache2-mpm-prefork や apache2-mpm-threaded ではなく、apache2-mpm-worker を使用する必要があることに注意してください。

次に、PHP リクエストを PHP-FPM 処理にルーティングするように Apache 仮想ホストを構成します。 Apache 構成ファイルに以下を記述します (Ubuntu 12.04 では、デフォルトのパスは /etc/apache2/sites-available/default です)。

1

2     AddHandler php5-fcgi .php

3     Action php5-fcgi /php5-fcgi

4     Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi

5     FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -idle-timeout 120 -pass-header Authorization

6

最後に、Apache プロセスと FPM プロセスを再起動します。

1 sudo service apache2 restart

2 sudo service php5-fpm restart

さらに読む

  • PHP マニュアル: PHP-FPM
  • PHP-FPM ホームページ
  • Ubuntu サーバー Maverick に Apache + mod_fastcgi + PHP-FPM をインストールする
  • mod_php がパフォーマンスに悪い理由

メールを送信

PHPメーラーを使用します。

PHPMailer 5.1 を使用してテストされました。

PHP は mail() 関数を提供しますが、これは非常にシンプルで簡単に思えます。残念ながら、PHP の多くの機能と同様、その単純さは誤解されやすいため、額面どおりに使用すると、重大なセキュリティ問題が発生しやすくなります。

電子メールは、PHP よりも曲がりくねった、痛みを伴う歴史を持つプロトコルの集合です。これに満足するということは、PHPmail() 関数が与えるべき感覚と同じように、電子メールを送信するときに混乱が多すぎることを意味します。

PHPMailer は、メールを安全に送信するためのシンプルなインターフェイスを提供する、人気のある完全なオープン ソース ライブラリです。疑問が解消されるので、より重要なことに集中できるようになります。

01

02 // Include the PHPMailer library

03 require_once('phpmailer-5.1/class.phpmailer.php');

04

05 // Passing 'true' enables exceptions. This is optional and defaults to false.

06 $mailer = new PHPMailer(true);

07

08 // Send a mail from Bilbo Baggins to Gandalf the Grey

09

10 // Set up to, from, and the message body. The body doesn't have to be HTML; check the PHPMailer documentation for details.

11 $mailer->Sender = 'bbaggins@example.com';

12 $mailer->AddReplyTo('bbaggins@example.com', 'Bilbo Baggins');

13 $mailer->SetFrom('bbaggins@example.com', 'Bilbo Baggins');

14 $mailer->AddAddress('gandalf@example.com');

15 $mailer->Subject = 'The finest weed in the South Farthing';

16 $mailer->MsgHTML('

You really must try it, Gandalf!

-Bilbo

');

17  

18 // Set up our connection information.

19 $mailer->IsSMTP();

20 $mailer->SMTPAuth = true;

21 $mailer->SMTPSecure = 'ssl';

22 $mailer->Port = 465;

23 $mailer->Host = 'my smpt host';

24 $mailer->Username = 'my smtp username';

25 $mailer->Password = 'my smtp password';

26  

27 // All done!

28 $mailer->Send();

29 ?>

メールアドレスを確認してください

filter_var() 関数を使用します。

Web アプリケーションが実行する必要がある一般的なタスク。ユーザーが有効な電子メール アドレスを入力したかどうかを確認するだけです。この問題を解決すると主張する複雑な式がオンラインで大量に見つかることは間違いありませんが、最も簡単な方法は、電子メール アドレスをチェックする PHP の組み込み関数 filter_var() を使用することです。

1

2 filter_var('sgamgee@example.com', FILTER_VALIDATE_EMAIL); // Returns "sgamgee@example.com". This is a valid email address.

3 filter_var('sauron@mordor', FILTER_VALIDATE_EMAIL); // Returns boolean false! This is *not* a valid email address.

4 ?>

さらに読む

  • PHP マニュアル: filter_var()
  • PHP マニュアル: フィルターの種類

HTML の入力と出力をサニタイズ

単純なデータ精製には htmlentities() 関数を使用し、複雑なデータ精製には HTML Purifier ライブラリ

を使用します。

HTML Purifier 4.4.0 でテスト済み

WBE アプリケーションでユーザー出力を表示する場合は、最初に出力を「サニタイズ」して、潜在的に危険な HTML を削除することが重要です。 悪意のあるユーザーが HTML を作成する可能性があり、Web アプリケーションによって直接出力されると、それを閲覧する人にとって危険になります。

正規表現を使用して HTML をサニタイズすることもできますが、それは行わないでください。 HTML は複雑な言語であるため、正規表現を使用して HTML をサニタイズしようとすると、ほとんどの場合失敗します。

strip_tags() 関数を使用することを提案する意見が見つかるかもしれません。 Stripe_tags() は技術的には安全ですが、入力が無効な HTML (終了タグがないなど) の場合、意図したよりも多くのコンテンツを削除する可能性がある「愚かな」関数になります。技術者以外のユーザーは通信で < および > 文字を使用することが多いため、strip_tags() は適切な選択ではありません。

「電子メール アドレスの検証」セクションを読んだ場合は、filter_var() 関数の使用を検討することもできます。ただし、filter_var() 関数には改行が発生した場合に問題があり、htmlentities() 関数の効果を近似するには直感的でない構成が必要になるため、これは良い選択ではありません。

単純なニーズのための浄化

Web アプリケーションが HTML を完全にエスケープする必要がある (つまり、完全に削除する必要はないが無害にレンダリングする) だけが必要な場合は、PHP の組み込み htmlentities() 関数を使用します。 この関数は、HTML の検証を行わず、すべてをエスケープするだけなので、HTML Purifier よりもはるかに高速です。

htmlentities() は、小さなサブセットだけでなく、適用可能なすべての HTML エンティティをエンコードするという点で、同様の関数 htmlspecialchars() とは異なります。

01

02 // 哦哦,用户的提交了一些恶意的html,我们需要将其在web 应用上显示!

03 $evilHtml = '
Mua-ha-ha!  Twiddling my evil mustache...
';

04  

05 // 用 ENT_QUOTES 确保单双引号被转义.

06 // 用 UTF-8 编码,如果文件被存储为UTF-8格式.

07 // 见本文的 UTF-8 小节

08 $safeHtml= htmlentities($evilHtml, ENT_QUOTES, 'UTF-8');

09 // $safeHtml 已经被完全转移你可以放心的输出显示了!

10 ?>

複雑なニーズに応える浄化

多くの Web アプリケーションでは、HTML をエスケープするだけでは十分ではありません。 HTML を完全に削除することも、HTML の小さなサブセットの存在を許可することもできます。その場合は、HTML Purifier ライブラリを使用してください。

HTML Purifier は十分にテストされていますが、比較的非効率なライブラリです。ニーズが複雑でない場合は、はるかに高速な htmlentities() を使用する必要があるのはこのためです。

HTML Purifier は、HTML を精製する前に検証するため、strip_tags() よりも優れています。これは、ユーザーが無効な HTML を入力した場合、HTML Purifier は、strip_tags() よりも HTML の元の意味を保持する点で優れていることを意味します。 HTML Purifier は高度にカスタマイズ可能で、HTML のサブセットのホワイトリストを作成して、HTML のこのサブセットのエンティティを出力に含めることができます。

欠点は、非常に遅く、セットアップが必要であり、共有ホスティング環境では実現できない可能性があることです。ドキュメントは複雑で理解しにくいことがよくあります。次の例は、基本的な使用構成です。 HTML Purifier が提供するさらに高度な機能については、ドキュメントを参照してください。

	<?php// Include the HTML Purifier libraryrequire_once(&#39;htmlpurifier-4.4.0/HTMLPurifier.auto.php&#39;);// Oh no!  The user has submitted malicious HTML, and we have to display it in our web app!$evilHtml=&#39;<div onclick="xss();">Mua-ha-ha!  Twiddling my evil mustache...</div>';// Set up the HTML Purifier object with the default configuration.$purifier=newHTMLPurifier(HTMLPurifier_Config::createDefault());$safeHtml=$purifier->purify($evilHtml);// $safeHtml is now sanitized.  You can output $safeHtml to your users without fear!?>

トラップ

  • 間違った文字エンコーディングで htmlentities() を使用すると、予期しない出力が発生する可能性があります。この関数を呼び出すときは、文字エンコーディングが指定されていること、およびそのエンコーディングがサニタイズする文字列のエンコーディングと一致していることを必ず確認してください。詳細については、「UTF-8」セクションを参照してください。
  • htmlentities() を使用する場合は、必ず ENT_QUOTES および文字エンコーディング パラメーターを含めてください。デフォルトでは、htmlentities() は一重引用符をエンコードしません。なんて愚かなデフォルトでしょう!
  • HTML Purifier は、複雑な HTML に対しては非常に非効率的です。 APC などのキャッシュ ソリューションをセットアップして、後で使用できるようにサニタイズされた結果を保存することを検討してください。

さらに読む

  • PHP HTML 精製ツールの比較
  • スタック オーバーフロー: XSS を防ぐためにstrip_tags() を使用しますか?
  • スタック オーバーフロー: PHP でユーザー入力をサニタイズする最良の方法は何ですか?
  • スタック オーバーフロー: 改行時の FILTER_SANITIZE_SPECIAL_CHARS の問題

PHP と UTF-8

一行だけの解決策はありません。配慮、細部への配慮、そして一貫性。

PHP の UTF-8 は最悪です。言葉の選択を許してください。

現在、PHP は低レベルで Unicode をサポートしていません。 UTF-8 文字列が正しく処理されることを確認する方法はいくつかありますが、それは簡単ではなく、HTML から SQL、PHP まで、Web アプリケーションのすべてのレベルを詳しく調べる必要があります。簡潔で実践的な概要を提供することを目指しています。

PHP レベルの UTF-8

2 つの文字列の連結や変数への文字列の代入などの基本的な文字列操作には、UTF-8 用の特別な操作は必要ありません。ただし、strpos() や strlen などのほとんどの文字列関数では、特別な考慮事項が必要です。これらの各関数には、対応する mb_* 関数があります (mb_strpos() や mb_strlen() など)。これらの対応する関数は、まとめてマルチバイト文字列関数と呼ばれます。これらのマルチバイト文字列関数は、Unicode 文字列を操作するために特別に設計されています。

Unicode 文字列を操作する場合は、mb_* 関数を使用する必要があります。たとえば、substr() を使用して UTF-8 文字列を操作すると、結果に文字化けが含まれる可能性があります。正しい関数は、対応するマルチバイト関数 mb_substr() である必要があります。

難しいのは、mb_* 関数の使用を常に忘れないようにすることです。一度忘れてしまったとしても、その後の処理中に Unicode 文字列が文字化けする可能性があります。

すべての文字列関数に対応する mb_* があるわけではありません。欲しいものが存在しない場合は、運が悪いです。

さらに、すべての PHP スクリプトの先頭 (またはグローバルに含まれるスクリプトの先頭) で mb_internal_encoding 関数を使用し、スクリプトがブラウザに出力する場合は mb_http_output() 関数を使用する必要があります。各スクリプトで文字列エンコーディングを明示的に定義すると、後で多くの問題を回避できます。

最後に、文字列を操作する多くの PHP 関数には、文字エンコーディングを指定できるオプションのパラメーターがあります。このオプションが存在する場合は、常に UTF-8 エンコーディングを明示的に指定する必要があります。たとえば、htmlentities() には文字エンコード オプションがあり、そのような文字列を処理する場合は常に UTF-8 を指定する必要があります。

MySQL レベル UTF-8

PHP スクリプトが MySQL にアクセスする場合、上記のすべての考慮事項に従っていたとしても、文字列を非 UTF-8 文字列としてデータベースに保存している可能性があります。

PHP から MySQL まで文字列が UTF-8 形式であることを確認するには、データベースとフォームの両方が utf8mb4 文字セットに設定されていることを確認し、データベース内の他のクエリと議論する前に MySQL クエリ「set names utf8mb4」に注意してください。 。例として、MySQL データベースへの接続とクエリの章を見てください。これは非常に重要です。

UTF-8 サポートを完了するには、「utf8」文字セットではなく、「utf8mb4」文字セットを使用する必要があることに注意してください。その理由については、「続きを読む」を参照してください。

ブラウザレベルで UTF-8 を使用します

mb_http_output() 関数を使用して、PHP がブラウザに出力するファイルが UTF-8 でエンコードされていることを確認します。 HTMLページファイルのタグの下に文字コードタグ(charsetタグ)があります。

01

02 // Tell PHP that we're using UTF-8 strings until the end of the script

03 mb_internal_encoding('UTF-8');

04

05 // Tell PHP that we'll be outputting UTF-8 to the browser

06 mb_http_output('UTF-8');

07

08 // Our UTF-8 test string

09 $string = 'Aš galiu valgyti stiklą ir jis manęs nežeidžia';

10

11 // Transform the string in some way with a multibyte function

12 $string = mb_substr($string, 0, 10);

13

14 // Connect to a database to store the transformed string

15 // See the PDO example in this document for more information

16 // Note the `set names utf8mb4` commmand!

17 $link = new PDO( 'mysql:host=your-hostname;dbname=your-db',

18 'your-username',

19 'your-password',

20 array(

21 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

22                         PDO::ATTR_PERSISTENT => false,

23                         PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'

24                     )

25                 );

26      

27 // Store our transformed string as UTF-8 in our database

28 // Assume our DB and tables are in the utf8mb4 character set and collation

29 $handle = $link->prepare('insert into Sentences (Id, Body) values (?, ?)');

30 $handle->bindValue(1, 1, PDO::PARAM_INT);

31 $handle->bindValue(2, $string);

32 $handle->execute();

33  

34 // Retrieve the string we just stored to prove it was stored correctly

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。