2009年2月25日水曜日

携帯サイトでのアクセス解析のBESTプラクティス

PHPを使う自分の場合、今のところこのやり方が良いと思う。


1.携帯からのアクセスかそれ以外(Bot/クローラーも含む)かを判別する

PHPで高速に携帯ゲートウェイのIPから携帯キャリアを判別する - グニャラくんのグニャグニャ備忘録@はてなで配布しているPythonプログラムを使ってIPアドレス判定PHPを作成する。(参考:floatingdays: PHPで携帯からアクセスを IPアドレスで判定


携帯キャリアのIPアドレス公表ページはこちら。変更されたらPHPを作り直す必要がある。


LinuxでApacheモジュールを入れられる環境なら、mod cidr lookupという手もある。


2.判定結果が"pc"の場合はGoogle Analyticsとかで解析する


3.判定結果が"pc"以外の場合は、myRTモバイルで解析する

PHPならリファラまで解析できるので、au・SoftBankは参照元サイトや検索キーワードの統計も見られる。
広告やリンクバック無しで無料なのはすごい。素晴らしい。

リアルタイムで見られるのは一部の情報のみで、多くの統計は見られるようになるまで時間がかかる。
その点、設置後すぐ見られるなかのひとの方が即効性・シンプルな使いやすさは上。
でも、検索キーワードの統計や着地ページを見られるなど総合力はmyRTモバイルの方が上。

なお、mod_rewriteを使っている場合はPHP埋め込みコードのgetenv('SCRIPT_NAME')をgetenv('REQUEST_URI')に変更しないといけないと思う。


4.それ以上の情報が欲しかったらWebサーバのアクセスログを解析する

AWStatsとかanalogとかで。
画像の読み込みをしないBot/クローラーの情報が欲しかったらアクセスログを解析するしかない。



参考:DSAS開発者の部屋:携帯ゲートウェイのIPアドレス帯更新を効率的に確認する方法 (今ではちょっと情報が古い)

PHPで携帯からアクセスを IPアドレスで判定

PHPで高速に携帯ゲートウェイのIPから携帯キャリアを判別する - グニャラくんのグニャグニャ備忘録@はてなを使うと簡単に判定できる。

Python3.0では動かなかったが、Python2.6にしたら動いた。

PHPファイルとして保存する内容は標準出力に出るので、ファイルへ出力して保存する 。

携帯キャリアのIPが変わったらPHPも作り直す。


(2009/02/25 追記)
WILLCOMはIP公表ページのURLが変わっていた。しかし新しいURLに変更しても、判別ロジックに現れない。IPアドレスの書き方が違うから拾えない?
どちらにしろWILLCOMはフルブラウザ?なら携帯扱いしなくてもいいかも。

2009年2月16日月曜日

PHPで FTP送信する例

メモ。

function ftp($host, $user, $password, $pathTo, $pathFrom, $mode = FTP_ASCII) {
 //FTP接続
 $conn = ftp_connect($host);
 if (!$conn) {
  throw new Exception('FTP接続失敗 ' . $host);
 }
 if (!ftp_login($conn, $user, $password)) {
  ftp_close($conn);
  throw new Exception('FTP認証失敗 ' . $user);
 }

 //ファイルを送信する
 $result = ftp_put($conn, $pathTo, $pathFrom, $mode);
 ftp_close($conn);

 if (!$result) {
  throw new Exception('FTP送信失敗');
 }
}

PHPで AES方式 (Rijndael-128)で暗号化するメモ

(2012/12/01追記)
手っ取り早くPHPで暗号化したいなら、CodeBook.phpを使うのがお勧め。
(追記終わり)


AESとは?
暗号化方式の1つ。ブロック長は128bitsのみ、鍵長は128・192・256bitsの3つから選択できる。
AESの元となる暗号化方式はRijndaelだが、Rijndaelではブロック長についても128・192・256bitsから選択できるという違いがある。


PHPでの使用例(CBCの場合)

$key = '秘密の合言葉';
$text = '暗号化するメッセージ';

srand();

$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
$hex = bin2hex($encrypted);

$bin = pack('H*', $hex);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $bin, MCRYPT_MODE_CBC, $iv);

echo $text . ' => ' . rtrim($decrypted);
  • AESのブロック長は128bits = 16Bytesなので、サイズは16決めうちでも良いかも。
  • CBCの初期化ベクトル(IV)は毎回違うものを生成しないといけない(参考:ブロック暗号モード(block cipher mode))ので、暗号化したデータと一緒にIVの値も渡さないと復号できない。
  • IVは第3者に見られても問題ない。IVが分かってもKEYが分からなければ復号は不可能だし、毎回違うIVを生成する限り(ECBの場合のように)データの一部を推測することも不可能。(ただしデータの最初のブロックの中身を知っている場合は、その部分を変更できるようだ。参考:PHPのmcrypt関数で使用する初期化ベクトル(IV)とは公開されてはまずいものなのでしょうか? (中略)人力検索はてな
  • 暗号化したデータ(およびIV)はそのままではバイナリなので、http等で渡すにはhexにしてから渡す。(参考:[PHP-users 13878] Re: hex2bin??PHP: pack - Manual
  • 復号した文字列は、文字列長が足りない分に\0が入っているのでrtrim()で削除。ただし元々のデータに\0が入りうる場合はそれなりの対処が必要。(参考:「PHPで暗号化・復号あれこれ」の続き - Do You PHP はてな
  • Java等、\0以外でパディングするプログラムと連携する場合はパディング方法が同じになるよう注意すること。
  • MCRYPT_RANDを使う場合は事前にsrand()する必要がある。
    注意: MCRYPT_RAND を使用する場合、乱数生成器を初期化するために、 必ず mcrypt_create_iv() の前に srand() をコールしてください。rand() のように、自動的に 初期化されるわけではありません。


モードがECBの場合
$key = '秘密の合言葉';
$text = '暗号化するメッセージ';

srand();
$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB, $iv);
$hex = bin2hex($encrypted);

//暗号化に使ったのと別のIVを使ってみる
$iv2 = mcrypt_create_iv($size, MCRYPT_RAND);
$bin = pack('H*', $hex);

$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $bin, MCRYPT_MODE_ECB, $iv2);

echo bin2hex($iv) . ' : ' . bin2hex($iv2) . '<br />';
echo $text . ' => ' . rtrim($decrypted);
  • ECBの場合、実際にはIVは使っていないので、別のIVでも復号できる。
  • でもmcrypt_encrypt()にIVを渡さないとWarningが出る。(Warningが出ても、暗号化・復号はできる。)
    Attempt to use an empty IV, which is NOT recommend


鍵長についてPHPのラインダールでは鍵長は128・192・256bitsの3つ全てをサポートしている。
print_r(mcrypt_module_get_supported_key_sizes(MCRYPT_RIJNDAEL_128));

array(3) {
 [0]=>int(16)
 [1]=>int(24)
 [2]=>int(32)
}

鍵の長さが鍵長より短い場合、NULL文字(\0)によりパディングされる。
PHPのラインダールでは鍵長を指定するパラメータが無いので、鍵長は渡した鍵の長さに応じて決まる。
実験したところ、渡した鍵が収まるうちで最も小さい鍵長が使われることが分かった。
(実験用のfunction)
//同じKEYか確かめるfunction
function is_same_key($key1, $key2) {
 $text = '暗号化するメッセージ';
 srand();
 $size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
 $iv = mcrypt_create_iv($size, MCRYPT_RAND);
 $encrypted1 = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key1, $text, MCRYPT_MODE_CBC, $iv);
 $encrypted2 = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key2, $text, MCRYPT_MODE_CBC, $iv);
 return ($encrypted1 === $encrypted2);
}
//足りない分をNULL文字で埋めるfunction
//(str_pad()では\0によるパディングが上手くいかなかった)
function pad($str, $len) {
 for ($i = strlen($str); $i < $len; $i++) {
  $str .= "\0";
 }
 return $str;
}
  • 鍵の文字列が15Bytesの場合、鍵長は16Bytes
    $key = str_repeat('a', 15);
    var_dump(is_same_key($key, pad($key, 16))); //true
    var_dump(is_same_key($key, pad($key, 24))); //false
    var_dump(is_same_key($key, pad($key, 32))); //false
  • 鍵の文字列が16Bytesの場合、鍵長は16Bytes
    $key = str_repeat('a', 16);
    var_dump(is_same_key($key, pad($key, 16))); //true
    var_dump(is_same_key($key, pad($key, 24))); //false
    var_dump(is_same_key($key, pad($key, 32))); //false
  • 鍵の文字列が17Bytesの場合、鍵長は24Bytes
    $key = str_repeat('a', 17);
    var_dump(is_same_key($key, pad($key, 16))); //true
    var_dump(is_same_key($key, pad($key, 24))); //true
    var_dump(is_same_key($key, pad($key, 32))); //false
  • 鍵の文字列が24Bytesの場合、鍵長は24Bytes
    $key = str_repeat('a', 24);
    var_dump(is_same_key($key, pad($key, 16))); //true
    var_dump(is_same_key($key, pad($key, 24))); //true
    var_dump(is_same_key($key, pad($key, 32))); //false
  • 鍵の文字列が25Bytesの場合、鍵長は32Bytes
    $key = str_repeat('a', 25);
    var_dump(is_same_key($key, pad($key, 16))); //true
    var_dump(is_same_key($key, pad($key, 24))); //true
    var_dump(is_same_key($key, pad($key, 32))); //true
  • 鍵の文字列が32Bytesの場合、鍵長は32Bytes
    $key = str_repeat('a', 25);
    var_dump(is_same_key($key, pad($key, 16))); //true
    var_dump(is_same_key($key, pad($key, 24))); //true
    var_dump(is_same_key($key, pad($key, 32))); //true


Windowsの場合のmcryptのセットアップ方法
php.iniでmcryptモジュールを有効にすれば使えた。
extension=php_mcrypt.dll
mcrypt_create_iv()の第2引数には注意。
Windows でサポートされているのは MCRYPT_RAND のみです。なぜなら、Windows には(当然) /dev/random あるいは /dev/urandom が存在しないからです。


Linux(CentOS)の場合のmcryptのセットアップ方法

yumでインストールする。(参考:floatingdays: PHPに後からmb_stringを追加する方法
yum install php-mcrypt
通常はこれでOK。
自分の環境の場合、インストールされたphp-mcryptはバージョンは5.1.6で、PHPのバージョンがなぜか5.2.5だったのでmcryptが有効にならなかった。(参考:使えるねっと :: トピックを表示 - mcryptのインストールについて
どうやらこのPHPはutterramblingsからインストールしたようだ。なのでphp-mcryptもutterramblingsからインストール。これで無事に mcrypt_list_algorithms() できた。



参考(AESについて):
 AES暗号 - Wikipedia(RijndaelのBit長については他のサイトの記述と違う?)
 The AES-CBC Cipher Algorithm and Its Use with IPsec
 ブロック暗号(block cipher)

参考:(PHPで暗号化)
 PHP: mcrypt_encrypt - Manual
 ウノウラボ Unoh Labs: PHPで暗号化・復号あれこれ
 mcryptの動作がマニュアルと違うように見える件 - yandodの日記

参考(Javaの場合):
 Java「AES暗号」メモ(Hishidama's AES Sample)
 Cipher (Java Platform SE 6)
 PHPとJAVAの暗号・復号の連携-教えてR2! ~ the last summer of C-3PO ~
 簡単な暗号化 - Java編

参考(Perlの場合):
 Crypt::CBC - 暗号ブロック連鎖(Cipher Block Chaining)モードでデータを暗号化します

参考(PKCS#5のパディングについて):
 68user's page 掲示板: 過去ログ
 PHP: Mcrypt Functions - Manual(pkcs5_pad() / pkcs5_unpad())
 StackTrace Blog - Blowfishによる暗号化・復号をJava→PHPで行う

その他の参考:
 ASCIIコードによる文字表現(NULL文字等について)

Apacheモジュール版の v8cgiがリリースされていた

v8cgiのバージョン0.3.0がリリースされ、Apacheモジュールとして動作させられるようになった。


httpd.conf設定例(Windowsの場合)

LoadModule v8cgi_module C:/test/v8cgi/mod_v8cgi.dll
AddHandler v8cgi-script .ssjs

Apacheモジュールとして動作させる場合、ssjsファイルの方の1行目に"#!/test/v8cgi/v8cgi"を書かなくてもよい。


ただし手元の環境では、Apache(再)起動後に最初に読み込んだssjsファイルが毎回実行される。
つまり、最初に/test/example.ssjsを表示させたら、/test/example2.ssjsでも/test/not-exist.ssjsにアクセスしてもexample.ssjsが実行される。
Zend Frameworkライクな(M)VCパターンにするならよいかもしれない。


参考:floatingdays: v8cgiのインストールと簡単なサンプル

PHPで Linuxのファイルパーミッションを取得・変更する方法

メモ。

//パーミッションの変更
chmod($path, 0666); //8進数で指定する

//パーミッションの取得
clearstatcache(); //fileperms()はキャッシュをクリアしてから
$perms = substr(sprintf('%o', fileperms($path)), -4);

echo $perms; // => 0666


参考:
 PHP: chmod - Manual
 PHP: fileperms - Manual

2009年2月11日水曜日

MySQLの TEXT型の列に INDEXを付ける

MySQLでTEXT型の列に普通にINDEXを付けようとするとエラーになる。

MySQL Error Number 1170
BLOB/TEXT column 'desc' used in key specification without a key length

が、長さを指定してINDEXを付ければOK。
ALTER TABLE `test`.`members` ADD INDEX `Index_2`(`desc`(100));

長さは255まで。それ以上だとWarningが出て、255になった。
Warning: Specified key was too long; max key length is 767 bytes

複合インデックスに絡めて定義はできないという話もあるが、手元のMySQL5.1では複合INDEXでも問題なくできた。

MySQLの FULLTEXTインデックスと MATCH AGAINSTによる検索

FLLTEXTインデックスについて

  • MyISAMのみ
  • 設定ファイルで検索対象の最低文字数を設定する(デフォルトは4)
    [mysqld]
    ft_min_word_len=1
  • TEXT型の列などにスペース区切り等で区切ったデータを入れ、FULLTEXTインデックスを付与する
  • 該当データが全体の50%を超えるような単語は検索対象から除外されるので注意
  • 日本語でもOK

FULLTEXTインデックスを付与された列は、MATCH AGAINSTによる検索ができる。
SELECT * FROM members
WHERE MATCH keywords AGAINST('メロン');

さらに、マッチはしないが関連しそうなデータも含める「クエリ拡張」というオプションもある。
SELECT * FROM members
WHERE MATCH keywords AGAINST('ソーダ' WITH QUERY EXPANSION);
「注記 :ブラインド クエリ拡張は関連性のない雑多な資料も戻しがちなため、検索フレーズが短い時にだけ使用することをお薦めします」そうだが。


参考:
 MySQL :: MySQL 5.1 リファレンスマニュアル :: 11.7 全文検索関数
 MySQL :: MySQL 5.1 リファレンスマニュアル :: 11.7.2 クエリ拡張を伴う全文検索
 [ヅラド] MySQL を使った全文検索 (Full-Text Search)
 MySQL FULLTEXT + Ngram : LIKE検索より数十倍高速な、お手軽 日本語全文検索 について|blog|たたみラボ

Photoshopで既存のファイルに別の画像ファイルを取り込む方法

初めてPhotoshopに触れた。WindowsのペイントツールやFlash(Playerではなく編集ツールの方)みたいに使えるかと思っていたが、Ctrl+C/X/Vが使えなかったりして使い勝手が全然違う。
既存のPhotoshopのファイルに別の画像ファイルを取り込む方法すら分からない。

哲さんの雑記帳: Photoshop CS2で2枚の写真を連結して、1枚の写真にする方法です。 JTrimですと簡単に出来ますが、あえてPhotoshopで挑戦してみました。(タイトル長い)を参考にしてやった分かった。

Windowを隣に並べてドラッグ&ドラッグすると。

さすがMac出身のソフト。マウスがメインか。

SimpleXMLで子要素を取り出すいろいろな方法

PHPのSimpleXMLオブジェクトで子要素を取り出すためのいろいろな方法のメモ。

元のXMLがこんな感じの場合、

$str = <<< XML_END
<?xml version="1.0" encoding="UTF-8" ?>
<root>

 <parent>

  <child>aaa</child>
  <child>bbb</child>
  <child>ccc</child>
  <count>3</count>
 </parent>
 <hy-phen>hyphen</hy-phen>
</root>

XML_END;

$xml = simplexml_load_string($str);

普通に子要素を取り出す場合
var_dump($xml->parent->count);

object(SimpleXMLElement)[5] string '3' (length=1)

繰り返しの子要素を同じように取り出そうとすると、1つ目だけ取り出してしまう
var_dump($xml->parent->child);

object(SimpleXMLElement)[4] string 'aaa' (length=3)

1つ目以外が欲しい場合はインデックスで指定できる
var_dump($xml->parent->child[2]);

object(SimpleXMLElement)[5] string 'ccc' (length=3)

繰り返しの子要素の全てを取り出す場合、foreachが使える
foreach ($xml->parent->child as $c) {
var_dump($c);
}

object(SimpleXMLElement)[3] string 'aaa' (length=3)
object(SimpleXMLElement)[6] string 'bbb' (length=3)
object(SimpleXMLElement)[3] string 'ccc' (length=3)

さらに、繰り返しの子要素だけでなく、子要素全てを取り出す場合はchildren()を使う
foreach ($xml->parent->children() as $c) {
var_dump($c);
}

object(SimpleXMLElement)[4] string 'aaa' (length=3)
object(SimpleXMLElement)[3] string 'bbb' (length=3)
object(SimpleXMLElement)[4] string 'ccc' (length=3)
object(SimpleXMLElement)[3] string '3' (length=1) ← childだけでなく、countも取れている

children()を使うと、繰り返しの子要素は配列にまとめられるようだ(foreachを使う分には意識することは無いけど)
var_dump($xml->parent->children());

object(SimpleXMLElement)[4]
 public 'child' => array
  0 => string 'aaa' (length=3)
  1 => string 'bbb' (length=3)
  2 => string 'ccc' (length=3)
 public 'count' => string '3' (length=1)


XML要素(タグ)の名前がPHPの変数名として使えない文字列の場合、{' '}で囲えばOK
var_dump($xml->{'hy-phen'});

object(SimpleXMLElement)[5] string 'hyphen' (length=6)

NameSpaceを使っている要素の場合、children()のパラメータとしてNameSpaceを指定しないとうまく子要素が取得できない
$children = $xml->children('http://...');
このとき、$childrenのさらに子要素を取得するためには$children->children()しないとなぜかうまく取得できない。
NameSpaceの指定がその子要素に引き継がれて、そのNameSpaceに該当する子要素のみ取得するようにフィルターがかかっている?
それがchidren()をパラメータ無しで呼ぶことによってフィルターが解除されるから?


参考:PHP: SimpleXML - Manual

MySQLの query_cache_sizeのチューニング

query_cache_sizeに値を指定することで、MySQLのクエリーをキャッシュさせレスポンスを向上させる。
デフォルトはゼロ。(キャッシュしない。)

現在の状態は下記SQLで取得できる。

SHOW STATUS LIKE 'Qcache_%';

  • Qcache_free_memory・・・キャッシュの空き容量。足りなければ増やす
  • Qcache_lowmem_prunes・・・キャッシュの容量不足で削除されたクエリーの数。これが多い場合もキャッシュサイズを増やす
  • Qcache_free_blocks・・・断片化したキャッシュのブロック。これが多い場合は下記SQLで断片化を解消する(1になる)。
    FLUSH QUERY CACHE;


キャッシュに関する状態は、MySQL Administratorでも見られる。


参考:
 [ThinkIT] 第6回:query_cache_sizeの違いによるパフォーマンス比較 (1/3)
 もろもろメモ : MySQL cache "query_cache_size" の設定

バッチ処理でWindowsのサービスを再起動する(応用編)

バッチファイルでWindowsのサービスを再起動する方法を使えば、タスクに登録したスケジュールで定期的にWindowsのサービスを再起動できる。
でも、Apacheなんかはたまに停止時にゴミプロセスが残っていたりして、直後の起動に失敗することがある。

そこで、起動を何度かリトライするようにしてみる。

@ECHO OFF

SET service_name=apache2

NET STOP %service_name%

SET max_count=3
SET loop_count=0

:service_start
 NET START %service_name%

 REM STARTできたら終わり
 IF %errorLevel% == 0 GOTO service_restart_end

 ECHO start失敗 (error level %errorLevel%)
 SET /A loop_count=%loop_count% + 1
IF NOT %loop_count% == %max_count% GOTO service_start

:service_restart_end

for文では変数の遅延展開がある(参考floatingdays: コマンドプロンプトで繰り返し処理)のに注意。(なのでGOTOを使ったループにした。)
また、GOTOを使ったループでは、間違えて永久ループにしないようにも注意。


関連記事:
 floatingdays: バッチファイルでWindowsのサービスを再起動する方法
 floatingdays: コマンドプロンプトで繰り返し処理


参考:
 コマンドプロンプトを使ってみよう! -バッチファイル-
 コマンドプロンプトで実行ファイルの戻り値を取得する:システム開発メモ:So-net blog

PDOの Prepared Statementと MySQLの Query Cache

MySQL で prepared statement を使うと query cache が効かないらしいので調査。


MySQL 5.0と 5.1.17 より前(=5.1.16以前)では、サーバサイドのPrepared Statementを使うとQuery Cacheが使われない。
参考:
 MySQL :: MySQL 5.0 Reference Manual :: 7.5.4 The MySQL Query Cache
 MySQL :: MySQL 5.1 Reference Manual :: 7.5.4 The MySQL Query Cache
 [PHP] prepared statement - Usenet Forums


でも、PDOのPrepared StatementはQuery Cacheを使っていると言う人もいる?(MySQLは5.0)
PHPのPDO::mysql。prepared statementはquery cacheを使っている! | まつぼっくりんご


また、PDOのPrepared Statementはそんなに有用じゃないから、$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true) した方がいいとか、PDO::query() を使った方がいいと言う人もいる。
Using PDO::MYSQL ? - Evil, as in Dr.(→ 機械翻訳:PDOを使うこと:MYSQLに?-悪(博士の場合のように)。
PHP: PDO::prepare - Manual


試したかったが、手元の環境は最新の5.1だったから普通にCacheが使われていた。

PHPの文字コード検出順の設定

メモ。

UTF-8はSJIS(SJIS-WIN)より前に。そうしないとUTF-8のサイトで文字化けする。

SJIS(SJIS-WIN)はEUC-JPより前に。そうしないとSJISのサイトで半角カナが(それ以外も?)文字化けする。(EUC-JPを使う場合はこれでは駄目かも?)

ASCIIは一番前で構わない。

JISはメールでしか使わないので、無しでもよいかも。その場合、メールで扱うときは明示的に指定する。



すると、例えばこんな感じで。

ASCII,UTF-8,SJIS-WIN,SJIS,EUC-JP,JIS

Flickr mobileの URL

PCで見る場合のFlickrのURL
 http://www.flickr.com/photos/maynard/3251629235/
 ↓
携帯で見る場合のFlickrのURL(User-Agentのチェックあり)
 http://m.flickr.com/photo.gne?id=3251629235&


ただし下記でも同じ写真のページを表示できる。(この場合もUser-Agentのチェックあり)
 http://m.flickr.com/photos/maynard/3251629235/
しかし、このURLの場合はページ内のユーザーのphotostreamページへのリンクがおかしくなってしまうので、m.flickr.comの方を使うほうが良さそう。

CakePHPで Cookieが有効になる PATHを指定する方法

CookieのPATHを指定すると、そのPATHに該当する場合のみCookieが有効になる。
SESSIONもCookieを使うので、SESSIONが有効になるPATHを限定または拡大できる。

例えばCookieのPATHが /foo の場合、
 Cookieが有効なURL
   http://example.com/foo
   http://example.com/foo/bar
 Cookieが無効なURL
   http://example.com/
   http://example.com/baz


CakePHPではCookieのPATHを指定したい場合、Sessionコンポーネントのpublic変数"path"にセットする。
AppControllerのbeforeFileterでやればアプリケーション全体に効く。

<?php
class AppController extends Controller {
 function beforeFilter() {
  $this->Session->path = '/foo';
 }
}

Dropboxの可愛い画像いろいろ

1. 新規会員登録後に送られてくるメールに付いている画像





2. 有料会員登録時に送られてくるメールに付いている画像

こちらで見られる → Dropboxを有料プランして良かったこと悪かったこと:[mi]みたいもん!

3. ページが見つからない場合(404 Not Found)の画像
4. エラー画面
こちらで → DropBoxのエラー画面 - SIMPLE*SIMPLE ~ ウェブ職人のための小粋なネタ帳 ~

IEと Firefoxと grayと grey

色として灰色を指定する場合、Firefoxではアメリカ流の"gray"でもイギリス流の"grey"でも、どちらでも表示できる。
しかし、IEでは"gray"しか対応していないので注意。

もっと注意なのが。薄灰色。IEではgrayへの対応とは反対に、なぜか"lightgrey"の方しか対応していない。



Firefoxの場合





IE7の場合(IE6も同様だった)

参考:
 Remember grey!=gray in IE CSS! - Democratic Underground
 灰色 - Wikipedia

2009年2月6日金曜日

衝撃スクープ!はてなが話題のPaaSでクラウドに参入!近日中に新サービスHatena::Serversをリリースか!?

これがそのスクリーンショット。


...

かと思ったら、はてな内部で使っているサービスらしい。
はてなでの仮想化技術の使い方@AMDセミナー - とあるはてな社員の日記内の一コマ。

どうもお騒がせしました。

最近EC2のことが頭から離れないもので...

ブログ アーカイブ

tags