Home > Archives > 2008-10

2008-10

PHP: クライアントへのCookieの設定と削除 - setcookie()関数

クライアントのブラウザにCookieを保存・削除する手順の練習をしてみました。

Cookieはサーバからクライアントへレスポンスを送信する際にヘッダに含まれる情報で、Cookie受信以降のクライアントのリクエストにはCookieの情報が含まれます。これによって、クライアントの識別や状態を管理することが出来ます。

Cookieをクライアントに送信する際は有効期限を設定し、削除する際はその有効期限を過去のものとして期限オーバーを装い、ブラウザに削除させます。

具体的に以下の例では、setcookie(<cookie名>[, <値>[, <有効期限>[, <送信パス>[, <送信ドメイン>[, <httpsのときのみの送信?>]]]]])でCookieを設定、削除します。cookie名には変数の他に配列も使用することが出来ます。

ソースコード

Cookieを用いたクライアントへの情報の保存とアクセスのカウント例です。クライアントブラウザ側からのリクエストに含まれるCookieへのアクセスには配列$_COOKIEを用います。

<?php
$available_time = time() + 1800; // 有効期限: 30分
$expire = time() - 1800;
if (isSet($_COOKIE['login_info'])) { // Cookieがセットされているか?
	// クッキーを削除
	setcookie("login_info[user_id]", "", $expire);
	setcookie("login_info[user_name]", "", $expire);
} else {
	// クッキーを保存
	setcookie("login_info[user_id]", "59816", $available_time);// 現時刻から30分有効のCookie
	setcookie("login_info[user_name]", "yukun", $available_time);
}
// アクセスのカウント
if (isSet($_COOKIE['count'])) {
	$count = $_COOKIE['count'];
	$count++;
} else {
	$count = 1;
}
setCookie('count', $count, $available_time);
?>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>クッキーの利用と削除</title>
</head>
<body>
<?php
if (isSet($_COOKIE['login_info'])) {
	echo "ユーザ情報のクッキーがセットされています。<br />\n";
	//echo $_COOKIE['login_info']['user_name'];などでアクセスしてもよい
	foreach ($_COOKIE['login_info'] as $key => $value) {
		echo $key . " → " . $value . " <br />\n";
	}
} else {
	echo "ユーザ情報のクッキーが保存されていません(初回読み込み時) or 削除されました)。<br />\n";
}
echo $count . "回目のアクセスです。<br />\n";
?>
</body>
</html>

実行結果

1回目のアクセス

ユーザ情報のクッキーが保存されていません(初回読み込み時) or 削除されました)。
1回目のアクセスです。

2回目以降のアクセス(偶数回)

ユーザ情報のクッキーがセットされています。
user_id → 59816
user_name → yukun
2回目のアクセスです。

3回目以降のアクセス(奇数回)

ユーザ情報のクッキーが保存されていません(初回読み込み時) or 削除されました)。
3回目のアクセスです。

このときのCookieの保持状況をブラウザで確認してみると、
ブラウザFirefoxでCookieを確認

ちゃっかりというかしっかり保存されていますね。次のアクセスの際、これを読み込み以下の項目を表示しますが、

user_id → 59816
user_name → yukun

直後に削除されます。

Cookieはクライアントを識別するのに便利な機能ですが、これは改ざんされる恐れもありセキュリティに注意して扱わなければなりません。なので、上の例のような分かりやすい配列名で重要なデータ(例えばパスワードなども)を扱うのも好ましくないようです。

クッキーを扱う際の注意点

  • ブラウザの設定によってはCookieをうけつけない。
  • 1つのCookieのサイズは最大4KBまで
  • 1つのドメインでは最大20個まで
  • Cookieの有効期限の判定はクライアントの時計に従う

Java: ローカルホスト名とIPアドレスを取得 - InetAddress.getLocalHost()メソッド

ローカルのホスト名とIPアドレスの取得方法です。
InetAddress.getLocalHost()メソッドでInetAddressクラスの唯一のインスタンスを取得し、getHostName()でホスト名を、getHostAddress()メソッドでIPアドレスをそれぞれ取得します。

これらの情報はコンピュータ一台に対して通常一つしかないので(LANカードが二枚以上さされている場合を除いて)InetAddressクラスはSingletonパターンを採っているようです。あー、アドレスを二つ以上持っている場合の手順忘れてしまいました。後でさらっておこう。

ソースコード

import java.net.InetAddress;
import java.net.UnknownHostException;

public class ShowInetAddress {
  public static void main(String[] args) {
    // ローカルホスト名とIPアドレスを取得
    try {
      InetAddress addr = InetAddress.getLocalHost();
      InetAddress addr2 = InetAddress.getLocalHost();
      if (addr.equals(addr2)) System.out.println("addrとaddr2は同じインスタンス");
      System.out.println("Local Host Name: " + addr.getHostName());
      System.out.println("IP Address     : " + addr.getHostAddress());
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
  }
}

実行結果の一例

addrとaddr2は同じインスタンス
Local Host Name: Yukun-PC
IP Address     : 192.168.1.10

Android: 10進数→2進数変換アプリ

試しに下図のような簡素な10進2進変換アプリを作ってみました。

以下は書いてみたコード。

ソースコード

res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Integer to Binary Calculator</string>
    <string name="label_description">10進数を2進数に変換表示</string>
    <string name="label_integer">10進数:</string>
    <string name="label_binary">2進数:</string>
    <string name="button_convert">変換</string>
</resources>

res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<linearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<textView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/label_description"
    />

<linearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    >
<textView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/label_integer"
    />
<editText android:id="@+id/text_integer"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:numeric="integer"
    android:maxLength="9"
    android:text=""
    />
</linearLayout>

<button android:id="@+id/button_convert"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="@string/button_convert"
	/>
<textView android:id="@+id/label_result"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text=""
    />
</linearLayout>

ITBCalculatorActivity.java

package info.yukun.android.itbcalc;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class ITBCalculatorActivity extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) { // アクティビティが生成される際に必ず呼び出される
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main); // UIのレイアウトを設定
    // 指定したリソース(R.java)インデックスからビュー(res/layout/main.xml)内のidのコンポーネント(ここではButton)インスタンスを取得
    Button button = (Button) findViewById(R.id.button_convert);
    button.setOnClickListener(convertToBinary); // ボタンが押された際のイベントを登録
  }

  // 登録するイベントリスナーはView.OnClickListenerを実装
  private View.OnClickListener convertToBinary = new View.OnClickListener() {
    public void onClick(View view) { // ボタンが押されたときに呼び出されるメソッド
      EditText textInteger = (EditText) findViewById(R.id.text_integer); // 入力値が入っているコンポーネントを取得
      String input = textInteger.getText().toString();
      if (input.equals("")) return;
      int intValue = Integer.parseInt(input);
      String binValue = Integer.toBinaryString(intValue); // 10進数整数を2進数文字列に変換
      TextView labelResult = (TextView) findViewById(R.id.label_result); // 結果を表示するTextViewを取得
      labelResult.setText("2進数:" + binValue);
    }
  };
}

Androidアプリを書いてみて

EditText android:id="@+id/text_integer"の属性android:maxLengthを"9"としたのは、変換メソッドInteger.toBinaryString(int value)の引数が32bit整数の為です。本当は属性値を10としてonClickメソッド内で32bitの範囲内(-2 147 483 647 ~ 2 147 483 647 = (2^31) - 1)か否かを判定したほうが良いと思うのですが、今回は端折りました。

ビジュアルエディタやXMLでUIのレイアウトを作っていくというのはFlexのmxmlに似てて取っ掛かり易い感じです。

C++, pthread: スレッドの同期と排他制御 - MutexとCondition Variable

以前、Boostライブラリを用いたスレッドの同期と排他制御を取り上げましたが、今記事はそれのpthreadバージョンです(似せただけです)。pthreadライブラリ自体はC言語から扱えますが、今回はstaticなメンバ関数を別スレッドで動かす練習も兼ねてC++で書いてみました。

ソースコード

#include <iostream>
using namespace std;

#include <stdio.h>
#include <pthread.h>

#define BUFFER_NUM 100
#define WAIT_NUM 1000000
#define LOOP_NUM 100

class HandleData {
public:
  HandleData()
  : index_(0), channel_array_len_(sizeof(channel_array_)/sizeof(channel_array_[0])), num_data_(0) {
    access_lock_ = PTHREAD_MUTEX_INITIALIZER;
    access_threshold_ = PTHREAD_COND_INITIALIZER;
  }

  // データの追加
  void putData(int n) {
    pthread_mutex_lock(&access_lock_); // スレッドにロックをかける
    while (index_ >= channel_array_len_) {
      printf("putData(): waitn");
      pthread_cond_wait(&access_threshold_, &access_lock_);
      // このスレッドを一時停止しロックを解除する(getData側のpthread_cond_signalが呼ばれるまで)
    }
    int i = index_;
    channel_array_[index_++] = n; // スレッドセーフなデータ格納
    printf("put: %2d in channel_array_[%2d]n", n, i);
    pthread_cond_signal(&access_threshold_);
    pthread_mutex_unlock(&access_lock_); // スレッドのロックを解除
  }

  // データの取得
  int getData() {
    pthread_mutex_lock(&access_lock_);
    while (index_ <= 0) {
      printf("getData(): waitn");
      pthread_cond_wait(&access_threshold_, &access_lock_);
      // このスレッドを一時停止しロックを解除する(putData側のpthread_cond_signalが呼ばれるまで)
    }
    num_data_ = channel_array_[--index_]; // スレッドセーフなデータ取得
    printf("get: %2d in channel_array_[%2d]n", num_data_, index_);
    pthread_cond_signal(&access_threshold_);
    pthread_mutex_unlock(&access_lock_);
    return num_data_;
  }

  // データを格納する関数(スレッド)
  static void *runPut(void *hd) {
    int wait_num = WAIT_NUM;
    HandleData *phd = reinterpret_cast<handleData*>(hd);
    for (int i = 0; i < LOOP_NUM; i++) {
      phd->putData(i);
      while (--wait_num); // 空回しで時間稼ぎ
      wait_num = WAIT_NUM;
    }
    return NULL;
  }

  // データを取得する関数(スレッド)
  static void *runGet(void *hd) {
    HandleData *phd = reinterpret_cast<handleData*>(hd);
    for (int i = 0; i < LOOP_NUM; i++) {
      phd->getData();
    }
    return NULL;
  }

private:
  pthread_mutex_t access_lock_; // 排他制御を行う変数(lock, unlock)
  pthread_cond_t access_threshold_; // 状態変数(waitしてlockを外す用途)
  volatile int index_;
  int channel_array_[BUFFER_NUM]; // putData()、getData()からアクセスされる変数
  const int channel_array_len_;
  int num_data_;
};

int main()
{
  pthread_t thr_put;
  pthread_t thr_get;
  HandleData hd;
  // スレッドの生成(走らせるのはstaticメンバ関数)
  pthread_create(&thr_put, NULL, HandleData::runPut, reinterpret_cast<void*>(&hd));
  pthread_create(&thr_get, NULL, HandleData::runGet, reinterpret_cast<void*>(&hd));

  pthread_join(thr_put, NULL);
  pthread_join(thr_get, NULL);

  return 0;
}

あまりこういった書き方はしないのだけれど。

実行結果の一例

put:  0 in channel_array_[ 0]
put:  1 in channel_array_[ 1]
put:  2 in channel_array_[ 2]
put:  3 in channel_array_[ 3]
get:  3 in channel_array_[ 3]
get:  2 in channel_array_[ 2]
<中略>
put: 96 in channel_array_[ 0]
get: 96 in channel_array_[ 0]
getData(): wait
put: 97 in channel_array_[ 0]
get: 97 in channel_array_[ 0]
getData(): wait
put: 98 in channel_array_[ 0]
get: 98 in channel_array_[ 0]
getData(): wait
put: 99 in channel_array_[ 0]
get: 99 in channel_array_[ 0]

pthreadで相互排他を行う際の注意点

boostのmutex::scoped_lockクラスであればデストラクタにロックの解除を任せられるので管理が楽ですが、pthreadでは「ロックする」、「ロック解除」の2ステップを必ず書かなければなりません。なのでロック中に予期せぬ例外やエラーの為関数などのスコープを脱する際もpthread_mutex_unlock()をし忘れていないか等の注意が必要です。

AS3でお絵かきFlashを作る (4)塗りつぶしと簡易レイヤーの操作

今記事で4回目ですねー。デモは以下のページに用意しました。
http://www.yukun.info/labs/flex/paint04/
今回の主な追加機能は、前回の改善点にも含まれていた
(1)長方形と楕円描画ツールへの「塗りつぶし」機能
(2)各描画図形間のレイヤー(重なり具合)移動機能
です。あと少しインスタンスの生成を押さえた処理に変更したので若干パフォーマンスが上がっているかと思います(約1割弱)。

まず、(2)のオブジェクト間の階層(レイヤー)移動機能ですが、これは描画した図形上で右クリックを押すことで呼び出せるコンテキストメニューから使えます(下図)。

Flexのペイントツールのコンテキストメニュー(レイヤー移動)

この機能で図形の重なり順序を調節することが出来ます。また、「配置」ツールで図形を選択するとその図形は自動的に最前面レイヤーに移動されます。これによって、マウスイベントの発生源を図形毎に持たせても、重なり具合によるイベントの取りこぼしか無くなる利点があります。結果、OOPにある程度沿ったプログラミングを行うことを可能にします。

ちなみにこのレイヤー移動アクションは履歴には記録せずundo、redoの対象にはしませんでした(このレベルのアプリに対しては必要ないかと思ったので)。もし貼り絵のように絵を描きたく、またundoを利用していきたい場合はPhotoshopやGIMP等の明確なレイヤー機構を実装したほうがすっきりすると思います。内部機能の実装の手間はさほど掛かりませんが、ツールボックスのようなUIを作らなくてはいけないのが今の私にとってメンドイところです。しかしFlexコンポーネントを学ぶ良い機会でもあるのでさわりだけでもやってみようかな。

こう機能が増えてくるとユーザインターフェース(UI)にもしっかり取り組まなければならないんですが、UIはリリースするプラットフォーム(PCデスクトップ上、PCブラウザ上、モバイル、スマートフォン)に依存する部分が大きいのでまだ取り掛かるのはいいかなと思ったり(ぉぃ)。

さて、今回で基本的なブラシツール(ベクター以外)は揃ったかと思いますので、そろそろテキスト系の機能を実装していきたいと思います。初回に「頭の中のアイディアを楽しくまとめられるツールを作ってみたい」とのたまっていたので(ならUIもしっかりやろう)、ちょっとチャレンジしてみます。合わせてベクターツールも追加してみます。

Page 1 of 3123

Home > Archives > 2008-10

バックナンバー
最近のコメント
最近のトラックバック
メタ情報

Return to page top