refirio.org
気ままな雑記帳&実験場。好き勝手に色々やっています。
エントリー
タグ「PHP」の検索結果は以下のとおりです。
Google App EngineでPHPを動作させるメモ
Google App Engineを少しだけ触ってみたのでメモ。
参考サイト
参考にはなったけど、色々端折られた個人メモみたいなので、自分用に改めてメモ。
環境構築
あらかじめWindowsに、Python2.7.xをインストールしておく。(GAEのツール自体がPythonで書かれているため、PHPを動作させる場合でも必要。)
プロジェクト作成
https://console.developers.google.com/project
から、プロジェクト名「GAE Test Project」、プロジェクトID「refirio-php-test」で新規にプロジェクトを作成する。(プロジェクト名とプロジェクトIDは任意のものを指定する。)
次に https://console.developers.google.com/project/refirio-php-test/start/appengine
にアクセスして解説に従う。
Google App Engine SDK for PHP をインストールし、サンプルコードをダウンロードする。サンプルコードは C:\localhost\home\gae\public_html\refirio-php-test
とか、ローカルの適当なディレクトリ内に配置する。
次にサンプルコードを編集する。.playground
の内容は以下のとおり。
{
"project_name": "PHP TEST - refirio",
"project_description": "Starter code for a Google App Engine app in PHP.",
"show_files": [
"helloworld.php",
"app.yaml"
],
"read_only_demo_url": "https://refirio-php-test.appspot.com/",
"download_filename": "appengine-try-php.zip"
}
app.yaml
の内容は以下のとおり。
application: refirio-php-test
version: 1
runtime: php55
api_version: 1
handlers:
- url: /.*
script: helloworld.php
helloworld.php
の内容は以下のとおり。
<?php
echo 'Hello, GAE!';
公開
デスクトップに作成されたショートカットから「Google App Engine Launcher」を起動する。ここからローカル環境でのテスト実行や、本番環境へのデプロイができる。
デプロイが完了すると、以下のURLからアクセスできる。
Basic認証設定ツール
100番煎じどころではないと思われるツールを作ったので置いておきます。
Basic認証をかけたいディレクトリ内に basic.php
などの名前でサーバにアップロードしてアクセスすると、作るべき .htaccess
と .htpasswd
の場所と内容を表示します。先頭に並んでいる test1
とかの部分は、認証させるユーザ名とパスワードです。適当に変更&増減できます。
.htaccess
の雛形を作ってくれたり .htpasswd
の内容を作ってくれたりするツールは多いけど、AuthUserFile
の内容を調べたりするのも面倒なのでそれも自動で。_(:3 」∠ )_
<?php
$users = array(
'test1' => '1234',
'test2' => '2345',
'test3' => '3456',
);
$path = dirname($_SERVER['SCRIPT_FILENAME']);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Basic Authentication</title>
</head>
<body>
<h1>Basic Authentication</h1>
<h2><?php h($path) ?>/.htaccess</h2>
<pre>AuthUserFile <?php h($path) ?>/.htpasswd
AuthGroupFile /dev/null
AuthName "Basic"
AuthType Basic
require valid-user
<Files ~ "^.(htpasswd|htaccess)$">
deny from all
</Files></pre>
<h2><?php h($path) ?>/.htpasswd</h2>
<pre><?php
foreach ($users as $username => $password) {
t($username . ':' . crypt($password) . "\n");
}
?></pre>
</body>
</html>
<?php
function h($data)
{
$data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
$data = nl2br($data);
echo $data;
}
function t($data)
{
$data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
echo $data;
}
?>
Webアプリケーションへの同時アクセス対策メモ
XAMPPの Apache Bench で同時アクセスを再現するメモ。テストした環境はWindows7。Apache Bench の使い方は以下を参考に。
XAMPPをCドライブ直下にインストールした場合、以下の手順で Apache Bench を使える。
> cd C:\xampp\apache\bin
> ab -n 15 -c 15 http://localhost/~test/ab/
「-n 15 -c 15」で「15人が同時にアクセスする(合計15回アクセス)」状況がテストできる。(「-n 15 -c 1」なら「1人が合計15回アクセスする」状況になるので、同時アクセスにはならない。)
以下で同時アクセスのテストとその対策を行う。
ファイルを使った例
<?php
/*
* No.2をカウントアップ(最大値100)
*/
if ($fp = fopen('logs/count.log', 'r+')) {
$data = '';
while ($line = fgets($fp)) {
list($id, $count) = explode("\t", rtrim($line));
if ($id == 2) {
if ($count < 100) {
$data .= "$id\t" . ++$count . "\n";
} else {
exit('Limit');
}
} else {
$data .= $line;
}
}
rewind($fp);
fwrite($fp, $data);
ftruncate($fp, ftell($fp));
fclose($fp);
} else {
exit('Error');
}
exit('Complete');
logs/count.log
の内容は以下のとおり。
1 10
2 20
3 30
4 40
5 50
これで上のPHPプログラムにアクセスすると、2の行が1カウントアップされる。何度もリロードすると、その回数だけカウントアップされる。
> ab -n 30 -c 30 http://localhost/~test/ab/count.php
30人の同時アクセスを発生させてみると、正しくカウントできないのが確認できる。
<?php
/*
* No.2をカウントアップ(最大値100)
*/
if ($fp = fopen('logs/count.log', 'r+')) {
flock($fp, LOCK_EX); //ファイルロック
$data = '';
while ($line = fgets($fp)) {
list($id, $count) = explode("\t", rtrim($line));
if ($id == 2) {
if ($count < 100) {
$data .= "$id\t" . ++$count . "\n";
} else {
exit('Limit');
}
} else {
$data .= $line;
}
}
rewind($fp);
fwrite($fp, $data);
ftruncate($fp, ftell($fp));
fclose($fp);
} else {
exit('Error');
}
exit('Complete');
ファイルロックを行えば、正しくカウントされるようになる。
データベースを使った例
<?php
/*
* No.2をカウントアップ(最大値100)
*/
try {
$pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$pdo->query('SET NAMES utf8');
$stmt = $pdo->prepare('SELECT count FROM count_test WHERE id = :id');
$stmt->bindValue(':id', 2, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if ($data['count'] < 100) {
$stmt = $pdo->prepare('UPDATE count_test SET count = count + 1 WHERE id = :id');
$stmt->bindValue(':id', 2, PDO::PARAM_INT);
$stmt->execute();
}
} catch (PDOException $e) {
exit($e->getMessage());
}
exit('Complete');
count_test
の定義は以下のとおり。
CREATE TABLE count_test(
id INT UNSIGNED NOT NULL,
count INT UNSIGNED,
PRIMARY KEY(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
これで上のPHPプログラムにアクセスすると、2の行が1カウントアップされる。何度もリロードすると、その回数だけカウントアップされる。
ab -n 200 -c 200 http://localhost/~test/ab/count.php
200人の同時アクセスを発生させてみると、正しくカウントできないのが確認できる。
<?php
/*
* No.2をカウントアップ(最大値100)
*/
try {
$pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$pdo->query('SET NAMES utf8');
$pdo->beginTransaction(); //トランザクション開始
$stmt = $pdo->prepare('SELECT count FROM count_test WHERE id = :id FOR UPDATE'); //行ロック
$stmt->bindValue(':id', 2, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if ($data['count'] < 100) {
$stmt = $pdo->prepare('UPDATE count_test SET count = count + 1 WHERE id = :id');
$stmt->bindValue(':id', 2, PDO::PARAM_INT);
$stmt->execute();
}
$pdo->commit(); //コミット
} catch (PDOException $e) {
$pdo->rollBack(); //ロールバック
exit($e->getMessage());
}
exit('Complete');
トランザクションと行ロックを行えば、正しくカウントされるようになる。
Windows + コマンドプロンプト + PHPUnit でユニットテスト
今更ながらPHPUnitを試したのでメモ。
概要
PHPUnit3で始めるユニットテストが解りやすかったが情報が古い。でも、概要をつかむには良さそうです。
大まかな内容としては「◯◯の命令を△△の形式で呼び出して、□□の結果が返ってくればOK」というコードをたくさん書いたプログラムを準備しておき、それを実行すれば各命令が正しく実行されたかを知ることができるというもの。(プログラム作成中に不具合を作ってしまっても、即座に検知できる…かもしれない。)
大人数で各々が大量の部品を作るような開発では、上手く導入するととても活躍してくれそう。一人/少人数で作成しているようなプログラムでは、使いどころが難しいかも。(自分が解っていないだけかも。)
導入自体は簡単。
導入
自分の環境に合わせて「Windows+コマンドプロンプト+PHPUnit」でPHPプログラムのテストをしてみたので、手順をメモ。PHPUnit のインストールを主に参考にしています。
まずは公式サイトから phpunit.phar
の安定版を入手する。
任意のディレクトリ内(C:\xxx\phpunit
とする)に、入手した phpunit.phar
を配置する。
C:\xxx\phpunit
内に phpunit.cmd
を作成し、以下の内容を記述する。(PHPへのパスは環境に合わせて設定する。)
@C:\xampp\php\php.exe "%~dp0phpunit.phar" %*
コマンドプロンプトで C:\xxx\phpunit
内に移動し、以下のコマンドを実行。以下のようにバージョン情報が表示されれば成功。
C:\xxx\phpunit>phpunit --version
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.
サンプルで動作確認
Getting Started with PHPUnit を参考にテスト。
上ページの内容を参考に C:\xxx\phpunit\src\Money.php
(テストしたいクラス)を作成。次に C:\xxx\phpunit\tests\MoneyTest.php
(テスト用プログラム)も作成。
コマンドプロンプトから、以下のようにコマンドを実行するとテストできる。
C:\xxx\phpunit>phpunit --bootstrap src/Money.php tests/MoneyTest
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.
.
Time: 31 ms, Memory: 4.00Mb
OK (1 test, 1 assertion)
上のように表示されればテスト成功。
自作のプログラムで動作確認
PHPUnit 用のテストの書き方 を参考にテスト。
まずは C:\xxx\phpunit\src\calculate.php
を作成し、掛け算と割り算の計算結果を返す命令を定義。これらの命令が正しく動作しているかテストするものとする。
<?php
function multiplication($x, $y) {
return $x * $y;
}
function division($x, $y) {
return $x / $y;
}
C:\xxx\phpunit\tests\calculate.php
を作成し、各命令をテストするコードを書く。(計算結果が正しく返ってくればテスト成功とする。)
<?php
require_once 'C:/localhost/home/test/public_html/phpunit/src/calculate.php';
class Calculate extends PHPUnit_Framework_TestCase
{
public function testCalculate()
{
$this->assertEquals(8, multiplication(4, 2));
$this->assertEquals(2, division(4, 2));
}
}
コマンドプロンプトからテスト実行。
C:\xxx\phpunit>phpunit tests/calculate
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.
.
Time: 30 ms, Memory: 4.00Mb
OK (1 test, 2 assertions)
上のように表示されればテスト成功。試しに関数の内容を間違ったものにしてテストすると。
FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
のような結果が表示されるので、正しくテストできていることが確認できる。
PHPでセッションハンドラを自作
PHPは標準機能でセッション管理ができますが、何故かセッション管理のみが正しく動作しないサーバーがあったので、セッションハンドラで対応してみた。
PHPでは標準命令の session_set_save_handler()
を使用すれば、セッションを扱う際の挙動を自分で決めることができます。(セッションをMySQLで管理する仕組みを自作したり、など。)
以下はファイルでセッションを管理するサンプル。
<?php
define('SESSION_HANDLER_PATH', dirname(__FILE__) . '/sessions/');
define('SESSION_HANDLER_PREFIX', 'session_');
define('SESSION_HANDLER_EXTENSION', '.log');
if (SESSION_HANDLER_PATH != '') {
$session_handler_path = SESSION_HANDLER_PATH;
} else {
$session_handler_path = '';
}
function session_handler_open($save_path, $session_name) {
global $session_handler_path;
if ($session_handler_path == '') {
$session_handler_path = $save_path;
}
return true;
}
function session_handler_close() {
global $session_handler_path;
return true;
}
function session_handler_read($session_id) {
global $session_handler_path;
$file = $session_handler_path . SESSION_HANDLER_PREFIX . $session_id . SESSION_HANDLER_EXTENSION;
if (file_exists($file)) {
return file_get_contents($file);
} else {
return null;
}
}
function session_handler_write($session_id, $data) {
global $session_handler_path;
$file = $session_handler_path . SESSION_HANDLER_PREFIX . $session_id . SESSION_HANDLER_EXTENSION;
return file_put_contents($file, $data);
}
function session_handler_destroy($session_id) {
global $session_handler_path;
$file = $session_handler_path . SESSION_HANDLER_PREFIX . $session_id . SESSION_HANDLER_EXTENSION;
unlink($file);
return true;
}
function session_handler_gc($lifetime) {
global $session_handler_path;
if ($dir = scandir($session_handler_path)) {
foreach ($dir as $entry) {
if (is_file($session_handler_path . $entry) and preg_match('/^' . preg_quote(SESSION_HANDLER_PREFIX, '/') . '\w+' . preg_quote(SESSION_HANDLER_EXTENSION, '/') . '$/i', $entry) and time() - filemtime($session_handler_path . $entry) > $lifetime) {
unlink($session_handler_path . $entry);
}
}
}
return true;
}
session_set_save_handler(
'session_handler_open',
'session_handler_close',
'session_handler_read',
'session_handler_write',
'session_handler_destroy',
'session_handler_gc'
);
?>
上のコードを一例ですが session_handler.php
という名前で保存し、同じディレクトリ内に sessions
というディレクトリを作成します。この中にセッションの情報が保存されます。
session_set_save_handler()
関数によって、「セッションを開始した時は session_handler_open()
が呼ばれる」「セッションを保存する時は session_handler_write()
が呼ばれる」のような設定を行っています。
以降は、以下のコードで自作のセッション管理を利用できます。
<?php
include_once('session_handler.php');
session_start();
if (isset($_SESSION['count'])) {
$_SESSION['count']++;
} else {
$_SESSION['count'] = 1;
}
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>サンプル</title>
</head>
<body>
<?php
echo $_SESSION['count'] . '回目のアクセスです。';
?>
</body>
</html>
include_once('session_handler.php');
でファイルを読み込む以外は、ごく普通のセッション利用サンプルです。
急きょ書いたコードなので変な箇所があるかもしれません。また、名前の重複を避けるためにもクラス化した方が良かったかも。と思っていたら、公式サイトにクラスのサンプルがあった…。またそのうち調べる予定。
PostgreSQLメモ
- 2013/10/24 14:27
- カテゴリー:制作, プログラム
- タグ:PHP, PostgreSQL
テーブルを扱うためのメモ。
SQLでテーブル一覧を表示
SELECT
pg_class.relname AS relname
FROM
pg_class INNER JOIN pg_namespace
ON
pg_class.relnamespace = pg_namespace.oid
WHERE
pg_class.relkind = 'r' AND pg_namespace.nspname = 'public';
SQLでテーブル仕様を表示
SELECT
column_name, data_type, is_nullable
FROM
information_schema.columns
WHERE
table_schema = 'public' AND table_name = 'テーブル名';
SQLでテーブル作成コードを表示
SELECT
CASE
WHEN tb.relkind = 'r' THEN(
SELECT 'CREATE TABLE "テーブル名"(' || chr(10) || array_to_string(
ARRAY(
SELECT ' "' || "Column" || '" '|| "Type" || "Modifiers" || "Index" FROM(
/* Column */
SELECT
at.attnum, ns.nspname AS schema, tb.relname AS table, at.attname AS "Column",
/* Type */
CASE
WHEN at.attinhcount <> 0 OR at.attisdropped THEN null
ELSE
CASE
WHEN tp.typname = 'int2' THEN 'SMALLINT'
WHEN tp.typname = 'int4' THEN 'INTEGER'
WHEN tp.typname = 'int8' THEN 'BIGINT'
WHEN tp.typname = 'float4' THEN 'REAL'
WHEN tp.typname = 'float8' THEN 'DOUBLE PRECISION'
WHEN tp.typname = 'bpchar' THEN 'CHAR'
ELSE UPPER(tp.typname)
END ||
CASE
WHEN at.attlen >= 0 THEN ''
WHEN at.atttypmod < 4 THEN ''
WHEN tp.typname <> 'numeric' THEN '(' || at.atttypmod - 4 || ')'
WHEN (at.atttypmod & 65535) = 4 THEN '(' || (at.atttypmod >> 16) || ')'
ELSE '(' || (at.atttypmod >> 16) || ',' || (at.atttypmod & 65535) - 4 || ')'
END
END AS "Type",
/* Modifiers */
CASE
WHEN at.attnotnull THEN ' NOT NULL'
ELSE ''
END ||
CASE
WHEN ad.adbin IS NULL THEN ''
ELSE ' DEFAULT ' || UPPER(pg_get_expr(ad.adbin, tb.oid))
END AS "Modifiers",
/* one-column Index */
CASE
WHEN ix.indexrelid IS NULL THEN ''
ELSE
CASE
WHEN ix.indisprimary THEN ' PRIMARY KEY'
WHEN ix.indisunique THEN ' UNIQUE'
ELSE ''
END
END AS "Index"
FROM
pg_attribute at
INNER JOIN pg_type tp ON at.atttypid = tp.oid
LEFT OUTER JOIN pg_attrdef ad ON ad.adrelid = tb.oid AND ad.adnum = at.attnum
LEFT OUTER JOIN pg_index ix ON ix.indrelid = tb.oid AND ix.indnatts = 1 AND at.attnum = ix.indkey[0]
LEFT OUTER JOIN pg_class ic ON ix.indexrelid = ic.oid
LEFT OUTER JOIN pg_am am ON ic.relam = am.oid
WHERE
tb.oid = at.attrelid AND at.attnum >= 1
) AS columns ORDER BY attnum
), ',' || chr(10)
)
||
(
SELECT
CASE
WHEN COUNT(*) = 0 THEN ''
ELSE ',' || chr(10) || ' ' || array_to_string(
ARRAY(
SELECT
CASE
WHEN indisprimary THEN 'PRIMARY KEY '
ELSE 'UNIQUE '
END
|| substr(indexdef, strpos(indexdef, '('), strpos(indexdef, ')') - strpos(indexdef, '(') + 1) || ' /* '||index||' */'
FROM
(
SELECT
ic.relname AS index, ns.nspname AS schema, tb.relname AS table --, ia.attname, ia.attnum
, ix.indnatts, ix.indisunique, ix.indisprimary, am.amname
, ix.indkey
, pg_get_indexdef(ic.oid) AS indexdef
FROM
pg_index ix
INNER JOIN pg_class ic ON ix.indexrelid = ic.oid
INNER JOIN pg_am am ON ic.relam = am.oid
WHERE
ix.indrelid = tb.oid AND ix.indnatts > 1 AND (ix.indisprimary OR ix.indisunique)
) AS def ORDER BY indisprimary desc, index
), ','||chr(10)
)
END
FROM
pg_index ix
WHERE
ix.indrelid = tb.oid AND ix.indnatts > 1 AND (ix.indisprimary OR ix.indisunique)
) || chr(10) || ')'
)
END
FROM
pg_class tb INNER JOIN pg_namespace ns ON tb.relnamespace = ns.oid
WHERE
tb.relname = 'テーブル名'
コマンドラインでデータベースの内容をエクスポート
pg_dump -U postgres -d データベース名 > C:\~エクスポート先~\任意のファイル名.sql
コマンドラインでデータベースの内容をインポート
psql -U postgres -d データベース名 -f C:\~インポート元~\インポートするファイル
PHPでデータベースの内容をエクスポート
putenv('PGHOST=ホスト名');
putenv('PGPORT=ポート番号');
putenv('PGUSER=ユーザー名');
putenv('PGPASSWORD=パスワード');
putenv('PGDATABASE=データベース名');
print('<pre>');
passthru('"C:\\postgresql\\bin\\pg_dump.exe" -i --inserts');
print('</pre>');
exit;
WindowsのXAMPPにPostgreSQLを導入するメモ
- 2013/09/11 13:58
- カテゴリー:制作, プログラム
- タグ:PHP, PostgreSQL
PostgreSQLを導入してみたので、忘れないうちにメモ。
主な参考サイト
トラブル
PHPからPostgreSQLに接続する際、以下のようなエラーになった。
Call to undefined function pg_connect()
php.ini
で php_pdo_pgsql.dll
と php_pgsql.dll
を有効にする必要がある。それでもダメなら、Windowsの環境変数にPHPへのパス(C:\xampp\php
など)を書き込めば回避できるみたい。
コマンドプロンプトからの操作例
#ユーザー名を指定してPostgreSQLにログイン
psql -U postgres
#ユーザー名とデータベースを指定してPostgreSQLにログイン
psql -U postgres -d test
#データベース作成
CREATE DATABASE test;
#データベース一覧
¥l
#データベース選択
¥c test
#テーブル作成
CREATE TABLE sample1(
id integer,
name text
);
#テーブル一覧
\dt
#テーブル定義確認
\d sample1
#SQLを発行
INSERT INTO sample1 VALUES(2, 'test2');
SELECT * FROM sample1;
PHPからの、pg_connect()での接続例
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>テスト</title>
</head>
<body>
<?php
$con = pg_connect('host=localhost dbname=test user=postgres password=1234');
if (!$con) {
exit('データベースに接続できませんでした。');
}
$result = pg_query($con, 'SELECT * FROM sample1');
while ($data = pg_fetch_array($result)) {
echo '<p>' . $data['id'] . ':' . $data['name'] . "</p>\n";
}
$con = pg_close($con);
if (!$con) {
exit('データベースとの接続を閉じられませんでした。');
}
?>
</body>
</html>
PHPからの、PDOでの接続例
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>テスト</title>
</head>
<body>
<?php
try {
$pdo = new PDO('pgsql:dbname=test;host=localhost', 'postgres', '1234');
} catch (PDOException $e) {
exit('データベースに接続できませんでした。' . $e->getMessage());
}
$stmt = $pdo->query('SELECT * FROM sample1');
if (!$stmt) {
$info = $pdo->errorInfo();
exit($info[2]);
}
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo '<p>' . $data['id'] . ':' . $data['name'] . "</p>\n";
}
$pdo = null;
?>
</body>
</html>
フレームワーク
オレオレフレームワークを作る機会があったので置いておきます。
本格的なフレームワークを導入するほどの規模ではないが、それなりに多機能なのである程度の処理は任せたい。今更PHP4に対応させる必要があるが、PHP5でも動作させる必要がある。本番環境のテストが公開直前までできないので、ひととおり内部を見渡せる軽量なフレームワークが好ましい。ついでに、簡易なデータベース管理ツールも欲しい。
…という場合に役に立つかもしれません。というか、そんなことがあったために自作することにした。_(:3 」∠ )_
PHPでオブジェクトを配列に変換
ググると色々出てきたものの、「オブジェクトの中に配列があって、さらにその中にオブジェクトがあって、さらにその中に配列がある」のような場合に正しく変換できなかったり、privateな値もまとめて取得したい場合に対応できなかったり…ばかりだったので書いてみた。
privateな値に直接アクセスできるようにするのは邪道な気もするけど、どうしても必要な時があったりなかったり。
function object2array($data)
{
if (is_object($data)) {
$data = (array)$data;
}
if (is_array($data)) {
foreach ($data as $key => $value) {
$key1 = (string)$key;
$key2 = preg_replace('/\W/', ':', $key1);
if (is_object($value) or is_array($value)) {
$data[$key2] = object2array($value);
} else {
$data[$key2] = (string)$value;
}
if ($key1 != $key2) {
unset($data[$key1]);
}
}
}
return $data;
}
使う時は
$array = object2array($object);
のように呼び出します。まだまだ調整の余地がありそうですが、ひとまずこれで。
PHPで可逆暗号化
PHPでは mcrypt_generic()
を使えば可逆暗号化ができ、mdecrypt_generic()
で復号化できます。…が、使い方がちょっとややこしかったのでメモ。関連する関数を色々と呼び出す必要があります。
具体的には、以下のコードで暗号化ができます。
<?php
//暗号化するデータ
$plain_text = 'これは秘密のメッセージです。';
//暗号化&復号化キー
$key = md5('KQAHGOEUXD');
//暗号化モジュール使用開始
$td = mcrypt_module_open('des', '', 'ecb', '');
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
//暗号化モジュール初期化
if (mcrypt_generic_init($td, $key, $iv) < 0) {
exit('error.');
}
//データを暗号化
$crypt_text = base64_encode(mcrypt_generic($td, trim($plain_text)));
//暗号化モジュール使用終了
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
//結果を表示
echo "<!DOCTYPE html>\n";
echo "<html lang=\"ja\">\n";
echo "<head>\n";
echo "<meta charset=\"utf-8\" />\n";
echo "<title>暗号化テスト</title>\n";
echo "</head>\n";
echo "<body>\n";
echo "<h1>暗号化テスト</h1>\n";
echo "<dl>\n";
echo "<dt>暗号化前</dt><dd>" . $plain_text . "</dd>";
echo "<dt>暗号化後</dt><dd>" . $crypt_text . "</dd>";
echo "</dl>\n";
echo "</body>\n";
echo "</html>\n";
?>
この場合、これは秘密のメッセージです。
という文字が暗号化されます。KQAHGOEUXD
は、暗号化と復号化に使うパスワードのようなものです。この値を知っている人だけが、このデータを復号化できます。
実行すると、以下のように暗号化前の文字と暗号化後の文字が表示されます。
暗号化テスト
暗号化前
これは秘密のメッセージです。
暗号化後
eVVX5OPG0Vj4L49cuq8A3KT1R2nljAIPn74vAw0d/QbYQ1CfUApMlqSpSkyDjDvi
復号化は以下のようにします。
<?php
//復号化するデータ
$crypt_text = 'eVVX5OPG0Vj4L49cuq8A3KT1R2nljAIPn74vAw0d/QbYQ1CfUApMlqSpSkyDjDvi';
//暗号化&復号化キー
$key = md5('KQAHGOEUXD');
//暗号化モジュール使用開始
$td = mcrypt_module_open('des', '', 'ecb', '');
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
//暗号化モジュール初期化
if (mcrypt_generic_init($td, $key, $iv) < 0) {
exit('error.');
}
//データを復号化
$plain_text = trim(mdecrypt_generic($td, base64_decode($crypt_text)));
//暗号化モジュール使用終了
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
//結果を表示
echo "<!DOCTYPE html>\n";
echo "<html lang=\"ja\">\n";
echo "<head>\n";
echo "<meta charset=\"utf-8\" />\n";
echo "<title>復号化テスト</title>\n";
echo "</head>\n";
echo "<body>\n";
echo "<h1>復号化テスト</h1>\n";
echo "<dl>\n";
echo "<dt>復号化前</dt><dd>" . $crypt_text . "</dd>";
echo "<dt>復号化後</dt><dd>" . $plain_text . "</dd>";
echo "</dl>\n";
echo "</body>\n";
echo "</html>\n";
?>
eVVX5OPG0Vj4L49cuq8A3KT1R2nljAIPn74vAw0d/QbYQ1CfUApMlqSpSkyDjDvi
は、先のコードで暗号化した文字列です。KQAHGOEUXD
は、暗号化したときと同じ値を指定します。
実行すると、以下のように表示されます。
復号化テスト
復号化前
eVVX5OPG0Vj4L49cuq8A3KT1R2nljAIPn74vAw0d/QbYQ1CfUApMlqSpSkyDjDvi
復号化後
これは秘密のメッセージです。
ユーティリティ
カテゴリー
タグクラウド
- 33分探偵1
- AMBITIOUS JAPAN!1
- ARIA2
- Air2
- Android2
- BLACK CAT2
- C#1
- Chrome2
- FINAL FANTASY2
- Flash2
- GAE1
- JavaScript18
- Kindle1
- Mac2
- MySQL7
- PHP68
- PayPal1
- Perl3
- PostgreSQL2
- Python1
- Ruby1
- SQLite6
- Switch1
- TinyMCE4
- Windows Media Player1
- bot1
- fragile1
- freo53
- iPhone3
- iTunes1
- levis1
- mod_rewrite2
- node.js1
- sola1
- true tears1
- いつかのメリークリスマス1
- いつか帰るところ1
- けいおん!1
- ここにしか咲かない花3
- とある魔術の禁書目録1
- とらドラ!2
- ひぐらしのなく頃に2
- みなみけ1
- イラスト4
- ガンダム003
- クロノトリガー1
- ザナルカンドにて4
- テラ1
- ニコニコ動画8
- ハゲタカ2
- ピアノ36
- マクロスF3
- ユニットテスト1
- ルパン三世1
- ローズ・オブ・メイ4
- 初音ミク1
- 半分の月がのぼる空1
- 名探偵コナン1
- 戦場のメリークリスマス5
- 携帯10
- 攻殻機動隊1
- 桜2
- 機工魔術士1
- 決行~姫をさがして~1
- 涼宮ハルヒの憂鬱10
- 深愛2
- 灼眼のシャナ4
- 聖剣伝説2
- 蕾3
- 蟲師2
- 返信2
- 野球1
- 鋼の錬金術師1