node.jsメモ
インストールしてちょっとだけ触ってみたのでメモ。
気ままな雑記帳&実験場。好き勝手に色々やっています。
カテゴリー「制作」の検索結果は以下のとおりです。
インストールしてちょっとだけ触ってみたのでメモ。
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');
でファイルを読み込む以外は、ごく普通のセッション利用サンプルです。
急きょ書いたコードなので変な箇所があるかもしれません。また、名前の重複を避けるためにもクラス化した方が良かったかも。と思っていたら、公式サイトにクラスのサンプルがあった…。またそのうち調べる予定。
Pythonをインストールした際のメモ。
httpd.conf
の AddHandler
に .py
を追加した。PythonからMySQLを使ってみる。MySQLに接続するためのドライバはたくさんあるけど、定番(のように思う)の MySQL for Python を使ってみる。
MySQL-python-1.2.4b4.win32-py2.7.exe
をダウンロードして実行するだけでインストールされる。以下はMySQLへの接続例。
#!/python/python
# coding: UTF-8
import MySQLdb
con = MySQLdb.connect(host='127.0.0.1', db='dbname', user='username', passwd='password', charset='utf8')
cur = con.cursor(MySQLdb.cursors.DictCursor)
cur.execute('SET NAMES utf8')
print 'Content-Type: text/html'
print ''
print '<!DOCTYPE html>'
print '<html>'
print '<head>'
print '<meta charset="utf-8" />'
print '<title>MySQL</title>'
print '</head>'
print '<body>'
cur.execute('SELECT id, name FROM members LIMIT 10')
result = cur.fetchall()
for row in result:
print '<hr />'
print 'id=' + str(row['id'])
print 'name=' + str(row['name'].encode('UTF-8'))
cur.close()
con.close()
print '</body>'
print '</html>'
localhost
で接続しようとすると Can't connect to MySQL server on 'localhost'
のエラーになった。IPアドレスなら接続できた。MySQLdb.cursors.DictCursor
を指定することにより、ディクショナリ形式で値を取得できる。1ファイルで構成されている軽量フレームワーク、Bottleを使ってみる。
Bottleをダウンロードすると含まれている bottle.py
を適当な場所にコピーする。
同じ場所に hello.py
を作成し、以下のコードを記述する。
from bottle import route, run
@route('/hello')
def hello():
return 'Hello World!'
run(host='localhost', port=8080, debug=True)
コマンドプロンプトから python hello.py
と入力すると、8080
でサーバーが起動する。ブラウザソフトから http://localhost:8080/hello
にアクセスし、Hello World!
と表示されれば成功。
CGIとして動作させる場合、以下のように記述する。
#!/python/python
# coding: UTF-8
import bottle
from bottle import route, run
@route('/hello')
def hello():
return 'Hello World!'
run(server=bottle.CGIServer)
ブラウザソフトから hello.py/hello
にアクセスし、Hello World!
と表示されれば成功。この方法なら、ロリポサーバーなどでも手軽に使える予感。
MySQLを扱う場合、Bottle-MySQLプラグインを使用する。(プラグイン内部では、前述の MySQL for Python が呼び出されている。)
bottle.py
と同じ場所に bottle_mysql.py
を配置すれば、以下のコードでMySQLに接続できる。
#!/python/python
# coding: UTF-8
import bottle
import bottle_mysql
from bottle import route, run
mysql_plugin = bottle_mysql.Plugin(dbhost='127.0.0.1', dbuser='root', dbpass='1234', dbname='test')
bottle.install(mysql_plugin)
@route('/')
def show(db):
db.execute('SELECT id, name FROM members LIMIT 10')
result = db.fetchall()
view = ''
for row in result:
view += '<hr />'
view += 'id=' + str(row['id'])
view += 'name=' + str(row['name'].encode('UTF-8'))
return view
run(server=bottle.CGIServer)
テーブルを扱うためのメモ。
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';
SELECT
column_name, data_type, is_nullable
FROM
information_schema.columns
WHERE
table_schema = 'public' AND table_name = 'テーブル名';
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:\~インポート元~\インポートするファイル
putenv('PGHOST=ホスト名');
putenv('PGPORT=ポート番号');
putenv('PGUSER=ユーザー名');
putenv('PGPASSWORD=パスワード');
putenv('PGDATABASE=データベース名');
print('<pre>');
passthru('"C:\\postgresql\\bin\\pg_dump.exe" -i --inserts');
print('</pre>');
exit;
Androidアプリは普通に書き出してインストールして簡単に完了したけど、iPhoneアプリはとても大変だったので参考にしたページをメモ。
ActionScript3 + Air で、Windowsのデスクトップに置いておけるガジェットを作成するメモ。以下のようなガジェットを作成できます。
基本的には普通のFlashと同じ手順で作れるけど、
のような仕様にしようとしたら、それなりにコードを書く必要があったのでメモ。
普通にウインドウを表示するとタスクバーに表示されるので、その対策にウインドウ非表示で起動して、ActionScriptからNativeWindowクラスで新しくウインドウを開く。Main
というクラスでムービークリップを作成して、それをActionScriptで新しいウインドウに配置する。…としています。
スタートアップへの登録は専用の命令で可能。表示位置の記憶はSharedObjectを使用。
具体的には、「ファイル → AIR 3.6 for Desktop 設定 → 詳細 → 初期ウインドウ設定」で「最大化を有効にする」「最小化を有効にする」「リサイズを有効にする」「起動後に表示する」のチェックを外した上で、以下のActionScriptでウインドウを表示する。
//アプリのデータを復元
var sharedObject:SharedObject = SharedObject.getLocal('App');
var appX:int = 100;
var appY:int = 100;
if (sharedObject.data.x) {
appX = sharedObject.data.x;
}
if (sharedObject.data.y) {
appY = sharedObject.data.y;
}
//スタートアップに登録
if (sharedObject.data.startup != true) {
NativeApplication.nativeApplication.startAtLogin = true;
}
//ウインドウを開く
var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions();
initOptions.transparent = true;
initOptions.systemChrome = NativeWindowSystemChrome.NONE;
initOptions.type = NativeWindowType.LIGHTWEIGHT;
var mainWindow:NativeWindow = new NativeWindow(initOptions);
mainWindow.stage.scaleMode = StageScaleMode.NO_SCALE;
mainWindow.stage.align = StageAlign.TOP_LEFT;
mainWindow.stage.stageWidth = this.stage.stageWidth;
mainWindow.stage.stageHeight = this.stage.stageHeight;
mainWindow.x = appX;
mainWindow.y = appY;
mainWindow.activate();
//メインのMCを配置
var m:Main = new Main();
m.x = Math.floor(m.width / 2);
m.y = Math.floor(m.height / 2);
mainWindow.stage.addChild(m);
//移動処理
m.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownToMove);
function mouseDownToMove(event:Event):void
{
mainWindow.startMove();
}
//終了処理
m.doubleClickEnabled = true;
m.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickToExit);
function doubleClickToExit(event:MouseEvent):void
{
closeWindow();
}
mainWindow.addEventListener(Event.CLOSING, closingToExit);
function closingToExit(event:Event):void
{
closeWindow();
}
function closeWindow():void
{
//アプリのデータを記録
var sharedObject:SharedObject = SharedObject.getLocal('App');
sharedObject.data.startup = true;
sharedObject.data.x = mainWindow.x;
sharedObject.data.y = mainWindow.y;
sharedObject.flush();
//終了
NativeApplication.nativeApplication.exit();
}
this.stop();
Mainムービークリップの内容は、基本的には普通のFlashと同じ要領で作れます。
まだまだ勉強中なので、ツッコミ歓迎…。_(:3 」∠ )_
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;
<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>
<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 」∠ )_
ググると色々出てきたものの、「オブジェクトの中に配列があって、さらにその中にオブジェクトがあって、さらにその中に配列がある」のような場合に正しく変換できなかったり、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);
のように呼び出します。まだまだ調整の余地がありそうですが、ひとまずこれで。
毎回探すのに手間取るのでメモ。「個人設定」にマウスオーバーでは一部のメニューしか表示されないので注意。
「ログイン」→「マイアカウント」→「個人設定」をクリック→「販売ツール」→「オンライン販売」→「PayPalボタン」で確認できる。
「ログイン」→「マイアカウント」→「個人設定」をクリック→「販売ツール」→「オンライン販売」→「ウェブサイトの設定」で「支払いデータ転送(オプション)」を「オン」にする。
「ウェブ ペイメントの自動復帰」を「オン」にし、「復帰 URL」にPDTを受け取るプログラムのURLを設定する。
「ログイン」→「マイアカウント」→「個人設定」をクリック→「販売ツール」→「支払いとリスク管理」→「即時支払い通知」