symfony の基礎 – セッションとスコープ

Action クラスにて

スコープ get 方法 set 方法 用途

インスタンス スコープ(ページ スコープ) echo $this->foo; $this->foo = “boo”; View でローカル変数のように参照可能

リクエストスコープ $this->getRequest()->getAttribute(“key”) $this->getRequest()->setAttribute(“key”,$value) リダイレクト時などアクション間でのデータ参照に利用

ユーザスコープ($_SESSION と同等) $this->getUser()->getAttribute(“key”) $this->getUser()->setAttribute(“key”, $value) ショッピングカートなどページ遷移のあるトランザクションで利用

J2EE でのスコープと照らし合わせて symfony での変数(データホルダ)の種類をリストアップしました。
(アプリケーションスコープについては必要性が薄いので割愛)
 
参考:
– パラメータホルダー(symfony book 日本語ドキュメント)

symfony – データベースを扱うには?

symfony ではデータベース処理に Propel を使っています。
次の手順を踏むことで、テーブルをオブジェクトとして扱うことが可能になります。
 
1. propel.ini の設定

<project_dir>/config/propel.ini

 

$ symfony propel-*-*

で利用するデータベース接続の設定.
propel.database.* の設定を変える以外はデフォルトでよい。

; unix socket 接続(TCP接続ならデフォルトにならえばよい)
propel.database.createUrl = mysql://root:dbpass@unix+/
propel.database.url = mysql://root:dbpass@unix+/dbname

 
2. databese.yml の設定

<project_dir>/config/database.yml

web,batch から利用する symfony の設定

all:
  propel:
    class: sfPropelDatabase
    param:
# dsn: mysql://root:[email protected]/dbname
# unix socket 接続
        phptype: mysql
        hostspec:
        database: dbname
        username: root
        password: dbpass
        port:
        encoding: utf8
        persistent:

3-1. DB, テーブルを設定ファイルから新しく作る場合,
こちら(symfony で開発日記)を参考に、

config/schema.yml

を以下のように設定する

propel:
  table1:
  table2:
    _attributes: { phpName: FooTable }
    table1_id:
    name: varchar(255)
    amount:
       type: integer
       unsigned:true
       notnull:true
    created_at:
    updated_at:

説明..
  propel: … 接続名。
  table1 が最低限のテーブル構造例(id カラムのみ持つ)。
  table2 については以下のカラムを定義している
     id … int not null auto_increment primary key。デフォルトで定義される。
     table1_id .. int 型。 <table_name>_id とすることで table_name に Foreign key を張る
     amount … amount int unsigned not null というカラム定義。
     created_at … DATETIME 型。symfony がレコード作成日時を自動挿入してくれる
     updated_at … DATETIME 型。symfony がレコード更新日時を自動挿入してくれる。
  また、table2 はモデルクラスにマッピングする時(後述)に、
   __attributes: { phpName: FooTable } で指定した名前(FooTable)でマッピングされます。
 
3-2. propel.ini で設定した名前の空の DB を作成する。

symfony propel-build-db

 
3-3. schema.yml から CREATE TABLE の SQL 文を生成する

symfony propel-build-sql

 
3-4. (3-3) で生成した SQL 文を実行してテーブルを作成する。

symfony propel-insert-sql

 
Note: 3-1 とは逆に既存 DB のテーブルから schema.yml を作成するには

symfony propel-build-schema

を実行します。
 
4. symfony プロジェクトで利用できるように schema.yml からモデルクラスを生成する

symfony propel-build-model

ここで生成したモデルクラスは

<project_dir>/lib/model/

以下に作成されます。
 
5. (4)で作成したモデルクラスを使い、symofony プロジェクト内で参照する

apps/app_name/modules/model_name/actions/actions.class.php

等で以下のようにして参照します(require,include は不要)。

public function executeIndex()
{
   // 最も簡単なレコード挿入の例
    // 新規レコード用インスタンスを生成
    $table1 = new Table1();
    // データベースに実際にレコードを書き込む
    $table1->save();
 
   // カラムに値を設定して挿入する例
    $fooTable = new FooTable();
    
    $fooTable->setTable1Id(1); // カラム table1_id に 1 を指定
    $fooTable->setName(“milk”); // カラム name に milk を指定
    $fooTable->setAmount(123); // カラム amount に 123 を指定
    // 書き込む
    $fooTable->save();
 
   // プライマリキーからカラムを取得し、削除する例
    // プライマリキーカラム(id)が 1 のレコードのインスタンスを取得する
    $fooTable = FooTablePeer::retrieveByPK(1);
    if($fooTable){
        // id = 1 のレコードがあれば削除
        $fooTable->delete();
    }
     
    // 更新の場合, 既存レコードを取得して変更後 save() すればよい。
     $fooTable = FooTablePeer::retrieveByPK(1);
     if($fooTable){
         $fooTable->setAmount(10);
         $fooTable->save();
     }
    
    // プライマリキー以外からレコードを得る場合は *Peer::doSelect(), doSelectOne() を使う
     // 単純に SELECT した場合の一番始めのレコードを取得
     $fooTable = FooTablePeer::doSelectOne(new Criteria());
     
     // name が milk で, 作成日時の古い順に全てのレコードを配列で取得
     $c = new Criteria();
     $c->add(FooTablePeer::NAME, “milk”); // 条件
     $c->addAscendingOrderByColumn(FooTablePeer::CREATED_AT); // ORDER
     $tables = FooTablePeer::doSelect($c);
     
}

Criteria クラスの利用方法については
The Definitive Guide to symfony
8 章(日本語)の Criteria についての項に詳細に書かれています。
なお、Criteria クラスの実体は symfony インストールフォルダの

vendor/propel/util/Criteria.php

で定義されています。
  
参考:
-symfony フレームワークテスト置場
  おおまかな手順、設定ファイルの設定の仕方、それぞれの意味など。
-symfony book 日本語ドキュメント コマンドラインインターフェイス

 symfony propel-*-*

についてはこちらを参照。
schema.yml がどこまで楽させてくれるか(symfony で開発日記)
  schema.yml の書き方についてまとめられています。
MySQL4.1以降+symfonyのときのdatabase.yml
  MySQL4.1 以降では encoding: utf8 を指定しないと化ける、とのこと。

文法チェック

GNU ChangeLog フォーマットでは TAB + * から始まる行が記事中にあってはいけないのか、chalow で文中で他のトピックとして扱われてしまいます。
 
なので、

cat ChangeLog | perl -ne ‘if(/\t[*]/ && !/\]:/){print “Line ” . $. . “:”;print;}’

として、

<tab>*

からはじまり、なおかつ

<tab>* …. [….]:

という書式を満たさない行を抽出して個別修正しました。

PHP5 MVC フレームワークの新スタンダード? symfony

http://www.symfony-project.com/
 
本日の「今更」その2。
 
CakePHP や Mojavi より symfony がいいかも。
 
と聞いていたので、とりあえずsymfony のインストールだけ。

$ pear channel-discover pear.symfony-project.com
$ pear install symfony/symfony

インストールの確認

$ symfony -V

と打てば

symfony version 1.0.3

のようにインストールしたバージョンが表示されます。
楽ちん。
 
なお、PHP ソースの configure 時に –enable-ctype をつけていないと
いざ使おうとした時に

PHP Fatal error: Call to undefined function ctype_alpha()

のようにエラーがでてしまいます。
(Windows の場合は ctype は標準で組み込まれているので問題ありません)
 
参考:
symfony.jp symfony の日本語情報 WiKi
– CodeZine: symfonyで始めるPHPフレームワーク

Ruby on Rails はじめの一歩

今更ですが、最近ようやく Rails を触ってみました。
 
– 10分で作る Rails アプリ for Windows
– Ruby on Rails 公式 – [http://www.rubyonrails.org/]
 
10 分でできる Rails アプリは、本当に 10 分で Ruby on Rails の手軽さが分かるのでお勧めです。
10分で作る…が Windows + MySQL なので,とりあえず FreeBSD で DB を使わない Hello World を表示する場合のメモを残しておきます。
 
あまりまとまったものではないですが..
 

 
1.Ruby + RubyGems をインストール
 FreeBSD の場合、Ruby, RubyGems のいずれも ports からインストール可能です(RubyGems は lang/ruby-extensions に含まれる)。

# portinstall lang/ruby lang/ruby-extensions

 
2. RubyGems の gem コマンドで Ruby on Rails をインストール

$ gem install rails

上のコマンドで一発インストール。依存関係について聞かれるのが嫌なら

$ gem install -y rails

とすればプロンプトなしでインストールされるはずです。
 
3.$rails アプリケーションサーバの構築

$ rails foo

このコマンドひとつで、カレントディレクトリに以下のものをすべてふくむフォルダ foo/ を作成します。
– 管理用スクリプト(script/)
  たとえば script/server はスタンドアロンサーバであり、
  script/generate は目的に応じたクラスやフォルダの自動生成を行うスクリプトです。
– 公開ディレクトリ(public/)
  実際の URL マッピングは public/.htaccess および、public/dispatches.cgi で行われています。
  rails サーバのデフォルトのトップページは public/index.html です。
  
-コントローラ格納フォルダ(app/controllers)
  MVC の controller 格納先
  サンプルとして最初からコントローラの雛型(app/controllers/Application.rb)が含まれています。
  コントローラ作成時はコマンド(scriot/generate controller <コントローラ名>) で作成すると便利です。
 
-ビュー格納フォルダ(app/views)
  MVC の view 格納先。
  ここに .rhtml (eRuby) 形式のテンプレートファイルで view を記述します。
-モデル格納フォルダapp/models)
  MVC の model 格納先。
  script/generate model <モデルクラス名> 等で作成したモデルが格納されます。
 
– 設定ファイル(config/)、
コントローラと URL のマッピングを設定する config/routes.rb,
アプリケーション上のすべての Ruby スクリプトに影響する環境設定を行う config/environment.rb,
MySQL 等のデータベース接続用の設定(アカウント、接続先 DB 名等)を設定する config/database.yml 等があります。
 
– アプリケーションで利用する追加 ruby ライブラリ格納フォルダ(lib/)
  ここにいれておくと ruby スクリプトでのrequire でパス指定なしで参照できるようになります。
  例: lib/my_library.rb があれば、rails アプリケーションからの参照時は require ‘my_library’ とするだけでよい。
 
4. コントローラ作成

script/generate controller Foo

  デフォルトでは HTTP リクエスト URL の最初のディレクトリ表記がコントローラ、次が呼び出すメソッド(action)となっています。
  たとえば

http://localhost:3000/foo/edit

へのアクセスは、ファイル app/controllers/foo_controller.rb の

FooController#edit()

が実行されます。
また、

http://localhost:3000/foo

のように、アクションを省略した場合は、Foo#index メソッドが呼び出されます。
一般的な Web サーバにおける index.html が、コントローラでは index メソッドとなると考えれば分かりやすいと思います。
 
 
5. Hello world を出力する(view, model を使わない場合)
ActionController::Base#render() を使うのが基本です。
具体的にはコントローラのアクション定義メソッド(例: FooController#index)を以下のようにします。
app/controllers/foo_controller.rb

# 前略
def index
    render :text => “hello world!!”
end
# 後略

 
6.コントローラでテキストの出力を行う(view を使う場合)
まず以下のファイルを作成します。
app/views/foo/index.rhtml

<html>
 <head>
   <title>Hello Example</title>
 </head>
 <body>
 <%= @message %>
 </body>
</html>

次に、さきほどのfoo_controller.rb の def index を次のように書き換えれば自動的に index.rhtml を参照します。

def index
   @message = “Hello, world!”
   render
end

具体的には、参照される view のファイル名は

app/<コントローラ名>/<アクション名>.rhtml

です。

IE6.0SP1以上で利用できるシステム制限

– Internet Explorer 6.0 SP1 で使用できる制限値(Microsoft)
http://support.microsoft.com/kb/823057/ja
 
Spybot の IE Tweaks 機能について気になって調べていて見付けました。
レジストリで設定すると、IE の機能の一部(例: メニューの項目等)を制限することが可能です。
例えば Spybot では

HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions

キーで、NoBrowserOptions = 1 (REG_DWORD)とすることで
ブラウザからインターネットオプションを開こうとした時に

このコンピュータの制限により、処理は取り消されました。システム管理者に問い合わせてください。

と出し実行できなくする、という機能を実現しています。
 
その他

NoSelectDownloadDir : [ファイルのダウンロード] ダイアログ ボックスの [保存] ボタンを無効にします。
NoViewSource : [表示] メニューの [ソース] を無効にします。ただし、ユーザーがソースを完全に表示できなくなるようにするには、NoBrowserContextMenu 値を追加する必要があります。
AlwaysPromptWhenDownload : [ファイルのダウンロード] ダイアログ ボックスの [この種類のファイルであれば常に警告する] チェック ボックスを淡色表示にし、常にオンに設定されるようにします。
NoTheaterMode : F11 キー (全画面表示モード) を無効にします。
NoBrowserContextMenu : Web ページを右クリックしたときに表示されるショートカット メニューを無効にします。
NoOpeninNewWnd : Ctrl + N キーおよび [開く] を無効にします。
NoBrowserSaveAs : [ファイル] メニューの [名前を付けて保存] を非表示にします。

などなど。
作品展示用のコンピュータなどで機能制限したい場合に有用かもしれません。
 
なお、セキュリティのため Policies 以下については、(HKEY_CURRENT_USER においても)管理者権限がないと追加、削除、変更ができないようになっています。

国際化(i18n:他言語対応)の基本

まず文字列の外部化をし、言語ごとにプロパティファイルを作成し、Java のクラスパス直下に置きます。たとえば Eclipse の場合 src ディレクトリ、それ以外の場合 class ディレクトリなど。
 
filename.properties: (対応していない場合のデフォルト. 英語が望ましい)

message.greet = Hello!!
message.bye = Good bye.

 
filename_ja.properties:
  日本語ロケール ja_JP の時に利用されるプロパティ.
  マルチバイト文字を扱う場合 native2ascii でエンコードする必要があるため、参考欄で後述する Eclipse の PropertiesEditor プラグインを使うとよい.

message.greet = こんにちは!!
message.bye = さようなら。

 
filename_fr.properties:
  フランス語ロケール fr_FR の時に利用されるプロパティ.
  このように対応したい言語用のファイルを追加するだけで言語対応ができます.

message.greet = Salut!!
message.bye = Au revoir.

 
以下が国際化対応した外部文字列呼び出しと時刻整形の Java サンプルコードです。

import java.util.ResourceBundle; // 外部文字列取得用
import java.text.DateFormat; // 日付表示用
// その他 import 文省略
 
// 略
 
public void main(String[] args){
   // 実行環境のデフォルトのロケールのプロパティファイルを読み込む
   ResourceBundle bundle =
       ResourceBundle.getBundle(“filename”); // <filename>_<言語コード>.properties の <filename> を指定。
    
   // 現在のロケールの言語で挨拶
   System.out.println(bundle.getString(“message.greet”));
 
   // 現在のロケールで有効な書式で日付表示
   String sToday = DateFormat.getDateInstance().format(new Date());
   System.out.println(sToday);
    
   // 現在のロケールの言語で別れの挨拶
   System.out.println(bundle.getString(“message.bye”));
  
}

結果:

– ロケールが英語(en_USなど)の場合:
Hello!!
May 31, 2007
Good bye.
 
– 日本語(ja_JP)の場合:
こんにちは!!
2007/05/31
さようなら。
 
– フランス語(fr_FR)の場合:
Salut!!
31 mai 2007
Au revoir.

 

java.util.Locale.setDefault(Locale.ENGLISH);

のようにすることで、以降のコードのデフォルトロケールを任意の言語,国に変更することができます。
 
参考:
国際化プログラミングの常識(@IT)
– Locale クラス(Javadoc)
– DateFormat クラス
PropertiesEditor
  .properties ファイルで日本語を含むマルチバイト文字を扱う時に便利な Eclipse プラグイン.
これを使うことでいちいち native2ascii を実行する必要がなくなります.
なお、スタンドアロン版(PropertiesEdotor.jar)もあります.
詳しい導入方法はこちらの記事(@IT)が参考になります。

PHP 用デバッガ

PHP: Advanced PHP Debugger(PHP) (php.net)

(PHP 公式ドキュメントより引用)
APD は進化した PHP デバッガです。PHP コードのプロファイリングや デバッグの機能を提供すること、また完全なスタックトレースを出力する 機能を提供することを目的として作成されています。

 
インストール手順:

$ pecl install apd
 
$ cat >> /path/to/php.ini ← エディタ等で以下の内容を php.ini に追加
 
zend_extension = /path/to/apd.so ← APD モジュールのフルパス(zend_extention 指定の場合は相対パスは不可)
apd.dumpdir = /tmp/apd_log ← APD での解析結果の出力先フォルダ
apd.statement_tracing = 0 ← 行単位トレースをする場合 1 にする。これを有効にすると出力が冗長になります。

Windows 用のコンパイル済み PECL モジュールは http://snaps.php.net/win32/ からダウンロードできます(ファイル名 pecl からはじまるもの)。
 
 
利用方法:
デバッグをしたいスクリプトの一番始めに

apd_set_pprof_trace();

を呼ぶと PHP デバッガが利用できます。
 
PHP デバッガによる結果は php.ini の apd.dumpdir で指定したディレクトリに

pprof.<プロセスID>.<通し番号>

のような形式で保存されます。
 
そのまま読めなくはないですが、読みやすい形に整形するために pprofp コマンドを利用することができます(APD に付属しています)。
 
— かかった処理時間の多い関数順に並びかえて出力する

pprofp -R [ファイル名]

— コールツリー(関数の実行順序)を調べる

pprofp -t [ファイル名]

— (上の二つ)+(ビルトイン関数は含めない)+(コールツリーの横に経過時間を表示)

pprofp -Rtci [ファイル名]

 
その他のオプションについては「APD の pprofp 引数一覧(pprofp -h)」を参照してください。
  
Windows 用の pprofp についてはAPD のソースに含まれるものが使えるのですが、そのままの形では使いにくいため、実行用のバッチファイルを作成したものを置いておきます。
 
Windows 対応 pprofp をダウンロード
(APD 1.0.1 ソース付属のものから作成)
 
– pprofp
– pprofp.bat
– pprof2calltree
– pprof2calltree.bat
の 4 ファイルが入っています。
この4ファイルをそのまま php.exe と同じ場所など適当にパスが通る場所に置いてご利用ください。
 
参考:
– APD(公式 PHP マニュアル)
cles::blog

PHP で OpenSSL

PHP で OpenSSL 関数を使ってみたので、定番のハローワールドを置いておきます。


OpenSSL 関数で暗号化、復号化を行うには、
暗号化、復号化に必要な鍵のペアを PEM 形式で生成する必要があります。
1. パスワード付き秘密鍵 private_password.pem を生成

$ openssl genrsa private_password.pem -des3 1024

2. (1)からパスワードのない秘密鍵 private.pem を生成

$ openssl rsa -in private_password.pem -out private.pem

3. (1)を削除

$ rm private_password.pem

4. (2)から公開鍵 public.pem を生成

$ openssl rsa -in private.pem -pubout -out public.pem

 


openssl_public_encrypt(), openssl_private
…公開鍵で暗号化し、秘密鍵で復号化します。
つまり、誰からでも暗号化して送れるが、内容を読めるのは秘密鍵を持っている人だけになるため、通信経路での傍受が不可能になり、内容が外部に洩れる心配がないので機密性が高くなります。
ただし誰でも暗号化できるので全く別の内容へのかいざんは可能であり、必ずしも信頼性はありません。
 

// 暗号化に使う公開鍵
$public_key = file_get_contents(“public.pem”);
 
// 暗号化する文字列
$message = “Hello, world!!”;
 
// 暗号化データの結果格納先
$encrypted = “”;
 
// 暗号化実行
if(!openssl_public_encrypt($message, $encrypted, $public_key)){
    echo “暗号化に失敗\n”;
    die;
}
 
// 暗号化結果を表示(そのままでは表示できないのでBASE64エンコードする)
echo “暗号化データ: \n “.base64_encode($encrypted) . “\n”;
 
$message = null;
// ———————
// 復号化
// ———————
// 暗号化に使った公開鍵に対応する秘密鍵
$private_key = file_get_contents(“private.pem”);
 
// 復号化結果格納先
$result = “”;
 
// 復号化実行
if(!openssl_private_decrypt($encrypted, $result, $private_key)){
    echo “復号化に失敗\n”;
    die;
}
 
// 結果出力
echo “復号化結果: \n ” . $result . “\n”
     “BASE64:\n” . base64_encode($result).”\n”; // 比較用

結果:

暗号化データ:
FmPaJ9jOmjl/mK249NqUPzYjPUHsmFkSuNyp0SMlgW1c9RRzmKXBjcRhXH/5fwTxItAcE8/
AlZkjYo27XvGR7a3hdXxgaXbk4VORdRRk8LJXKB+xlVzF48OlHJ5lKUrXUdfr2BFtx53/IH
431mBlYWDhf+KyW608eKAA0T34qRY=
復号化結果:
Hello, world!!
BASE64:
SGVsbG8sIHdvcmxkZmc=

 


openssl_private_encrypt(), openssl_public_decrypt() の例:
…秘密鍵で暗号化し、公開鍵で復号化します。
つまり、鍵の所有者しか暗号化できないので中身のかいざんも、経路での差し替えも不可能になり、内容についての信頼性が高くなります。
ただし誰でも読めるため、内容の機密性はありません。
 
秘密鍵、公開鍵の使い方を逆にする以外は上の例と全く同じです。

// 暗号化に使う秘密鍵
$private_key = file_get_contents(“private.pem”);
 
// 暗号化する文字列
$message = “Hello, world!!”;
 
// 暗号化データの結果格納先
$encrypted = “”;
 
// 暗号化実行
if(!openssl_private_encrypt($message, $encrypted, $private_key)){
    echo “暗号化に失敗\n”;
    die;
}
 
// 暗号化結果を表示(そのままでは表示できないのでBASE64エンコードする)
echo “暗号化データ: \n “.base64_encode($encrypted) . “\n”;
 
$message = null;
// ———————
// 復号化
// ———————
// 暗号化に使った秘密鍵から作られた公開鍵
$public_key = file_get_contents(“public.pem”);
 
// 復号化結果格納先
$result = “”;
 
// 復号化実行
if(!openssl_public_decrypt($encrypted, $result, $public_key)){
    echo “復号化に失敗\n”;
    die;
}
 
// 結果出力
echo “復号化結果: \n ” . $result . “\n”
     “BASE64:\n” . base64_encode($result).”\n”; // 比較用

結果:

暗号化データ:
CII4EW6LQBq0faVJxshUfk9VCdFsE66DnQPVdsLbvfq7tNCMzAIZbZA3GBxHu4cG2TqvOnn
xN9C9S9IgBIbulfj4c90IkrYtHQGt3RHAJBYiAgfmzCKbMr2cPJhZwkMUkjczXeaOD1htFJ
TL9e2RKsrWBVFIaiG1JgFk2Jyd928=
復号化結果:
Hello, world!!
BASE64:
SGVsbG8sIHdvcmxkZmc=


openssl_open(), openssl_seal() の例:
…同報メールのように、別々の公開鍵を持つ複数の相手に対して同じデータを暗号化して送る場合に使います
 
– 送信側(送信先1の公開鍵 user1_public.pem と送信先2の公開鍵 user2_public.pem を持っているとする. 自分の鍵は必要としない)

// 送り先の公開鍵一覧。
$pubkeys = array(
        file_get_contents(“user1_public.pem”),
        file_get_contents(“user2_public.pem”),
   );
 
// 送る内容
$real_message = “Hello, world!!”;
 
// 暗号化データの結果格納先
$encrypted = “”;
// 復号化に必要なエンベロープキーの格納先。$pubkeys の数だけ格納される。
$ekeys = array();
 
if(!openssl_seal($real_message, $encrypted, $ekeys, $pubkeys)){
    echo “暗号化に失敗しました\n”;
    die;
}
 
// 出力. エンベロープキーと暗号化データについてはバイトコードなので、表示のために BASE64 エンコードしています。
for($i = 0; $i < count($pubkeys); $i++){
    echo “送り先番号: $i\n” .
         “使った公開鍵: \n” .
         $pubkeys[$i] .”\n” .
         “対応するエンベロープキー: \n” .
         base64_encode($ekeys[$i]) .”\n” .
         “暗号化されたデータ: \n” .
         base64_decode($encrypted);
}

 
受信側(送信側からエンベロープキー $ekey と暗号化データ $encrypted を受け取っているとする):

// 送信側が暗号化に使った公開鍵(user1_public.pem)に対応する秘密鍵
$private_key = file_get_contents(“user1_private.pem”);
 
// 結果格納先。復号化した文字列が入る
$message = “”;
 
if(!openssl_open($encrypted, $message, $ekey, $private_key)){
    echo “復号化に失敗しました\n”;
    die;
}
 
// 結果表示
echo $message . “\n”;

 
送信側結果は次のようになります。


送り先番号: 0
使った公開鍵:


-BEGIN PUBLIC KEY—–
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzZFcKoXbuWzGvlv++7Y05/jBh
nYC+PM67v3H2I5pYV8tUz/6GqsG5afFgLJYoWPEd3KYXHb46B0GxEOydOTuTLEcv
+gVr6v4khgOgjxOcM1hlv+EvAThm1lIY1Y5lbTv+MEUyrGm7SDk8iUaHF6OBcQp3
NzkO6j3+YrsC8znXPwIDAQAB


-END PUBLIC KEY—–
対応するエンベロープキー:
lu4ON1xW2hrrS1jXfav6mjWD32+Iuz1Jk20vhDRmSsfEp3vXuij7Z0R/ClhpgE9MxDJADiU
LS/CCUPuiZ3wUDErccfUFGGgcBKFsoXOgcX/vSfhi8yCYu3BOD+h5fOMmg/ZVe6NMjCVq50
D8yce5gPoypg2LHijse+0R1bPil8o=
暗号化されたデータ:
0qf1eWjjaHkiqRFKijam


送り先番号: 1
使った公開鍵:


-BEGIN PUBLIC KEY—–
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzZFcKoXbuWzGvlv++7Y05/jBh
nYC+PM67v3H2I5pYV8tUz/6GqsG5afFgLJYoWPEd3KYXHb46B0GxEOydOTuTLEcv
+gVr6v4khgOgjxOcM1hlv+EvAThm1lIY1Y5lbTv+MEUyrGm7SDk8iUaHF6OBcQp3
NzkO6j3+YrsC8znXPwIDAQAB


-END PUBLIC KEY—–
対応するエンベロープキー:
Hpv4sE4M4RGnbEAPMqFKxOOPDJG0hpWBoIXCe8xUaIzx/dskUQ/a+T4jYyw+RRGh11wlzZt
CJOjzkP3pbafc0ymElAzS8RFAne7bVuCJh44UF55thAUo0nZVo1/2Wz9HuTDL23AYwc+jyh
U/k24bpGh81VJl5I7IkItoDeiS70Y=
暗号化されたデータ:
0qf1eWjjaHkiqRFKijam

受信側結果:

Hello, world!!

 
参考:
OpenSSL 関数(php.net)
 PHP マニュアルの OpenSSL 関数についての項目。
– OpenSSL 公式サイトの日本語訳サイト
更新は不定期のようですが、openssl のマニュアルが参考になります。
公式はこちらです。

他のアプリケーションのキーイベント等メッセージ監視

SetWindowsHookEx() という API を使うと、他のウィンドウに対するさまざまなイベントを監視することができます。
 
デフォルトの動作であるローカルフックだとそのアプリケーションに対するイベントしかとれません。他のウィンドウのイベントをとるキーロガー的な動作を実現するにはグローバルフックにする必要があります。
グローバルフックを行うには、DLL のハンドルを引数として渡さなければならないため、DLL で実装しなければなりません。
 
参考:
SetWindowsHookEx()(MSDN)
– 他のアプリケーションのメッセージを監視(doumo.jp)