2008年1月30日水曜日

 

正しいメールアドレスのチェック方法

正しいメールアドレスのチェック方法 / yohgaki's blog

正規表現でメールアドレスをチェックするのは面倒です。しかも、RFCを守らない大手企業もあり、正規表現でチェックするのは諦めるのが妥当でしょう。
記入されたメールアドレスが正しいかチェックする手順
  1. @でスプリットする
  2. 配列要素が2つかチェック。NGはエラー
  3. 1つ目の要素(ユーザ名部分)および2つ目の要素(ドメイン部分)に空白や制御文字、非ASCII文字が含まれていないかチェック。NGはエラー
  4. 2つ目の要素(ドメイン部分)がDNSのMXレコードを持つかチェック。NGはエラー
PHPのmail, mb_send_mail関数は関数レベルでメールヘッダインジェクション対策が施されているので、CR,LFが混じっていてもインジェクション攻撃に脆弱になりません。しかし、他の環境ではメールヘッダインジェクションが可能になる場合があります。最低限、CR、LFだけはチェックし、含まれる場合はセキュリティ上のエラーとして処理(攻撃が行われたとアラートを発生させる等)しなければなりません。
メール送信後の認証処理
  1. 認証URLを含むメールを送信
  2. 認証URLがリクエストされる
  3. 認証用の鍵が一致するかチェック。不一致はNG

メールアドレス認証等に使う鍵は十分なエントロピーを持ったデータのハッシュ値(SHA1など) 、PHPではuniqid()関数なんかを利用すると良いらしい。


$token = sha1('SOME_RANDOM_PREFIX' . uniqid(rand(), true));

迷惑メール防止のため一定時間は同じメールアドレスに対して認証用のメールを繰り返し送信しないようにする。

あとで考える。

関連
Web屋のネタ帳
Webアプリでメールアドレスを確認する「正しい」方法
ドコモもauもいいかげんにメールアドレス設定の仕様を直せ。

2008年1月29日火曜日

 

Tumblrのようなgelatoインストール

gelato cms

Liner Note
サーバインストール型tumblrクローン「gelato」をインストールしてみた
CREAMU
無料で使えるAjax,PHP,MySQLで作られたtumblelogCMS!『gelato』
yamaq blog
tumblrクローンのgelato
PatentBureau Lab.
gelato失敗。

インストール成功。DBがUTF-8じゃないと日本語はダメダメだけど、他に障害は無かった。
プラグインとか多言語化がChyrpの方が進んでるからそっち使いたいんだが。 WYSIWYGプラグインあるし。
あとはメールから投稿するプラグインがあれば良いなぁ。
Chyrpが全然上手くいかねー。(参照TumblrのようなChyrpインストール)
助けてー。


2008年1月25日金曜日

 

【Perl】文字コード変更いろいろ【文字化け】

メモ程度にまとめ。

Jcode.pm を使った場合 - Perl 5.8.0未満

use Jcode;

$str1 = "文字列の文字コードをUTF-8からShift-JISに変えます"
$str2 = Jcode->new( $str1, "utf8")->sjis;
//UTF-8だった文字列をShift-JISに変更
$str2 = Jcode::convert( $str1 , "sjis", "utf8" );
//上と同じ処理

文字コードの指定には、"jis"、"sjis"、 "euc"、"ucs2"、"utf8"が使えます
Encode モジュールを使った場合 - Perl 5.8.0以降

use Encode;

from_to($str, 'utf8', 'shiftjis');
//$strの文字コードをUTF-8からShift-JISに変更
jcode.pl を使った場合

require 'jcode.pl';
 jcode::convert(\$str, 'euc', 'sjis'); 
// $str の文字コードをShift-JIS から EUC に変換

jcode.plJcode.pmの前のもので、Perl 4でも動きます。

Perlでそうそう文字化けしない文字コード変換のやり方まとめ


use Encode;
use Encode::Guess qw/ascii utf8 euc-jp shiftjis 7bit-jis/;

my $dec = Encode::Guess->guess($str);
if (ref $dec) {
    # utf8フラグを付けた文字列を取得
    my $utf8str = $dec->decode($str);

    # 上と同じだが別のやり方
    my $utf8str = Encode::decode($dec->name, $str);

    # Shift_JISに変換した文字列を取得
    my $sjis_str =  Encode::encode('shiftjis', Encode::decode($dec->name, $str));

    # $strの中味をEUC-JPに変換
    Encode::from_to($str, $dec->name, 'euc-jp');
}
EncodeもEncode::Guessもperlの標準モジュールになってるから、相当古いPerlでもなければ入ってるはず。

ラベル: ,


2008年1月19日土曜日

 

【PHP】テンプレートファイルのSSI処理を置き換えるプログラム※追記

PHPからHTMLテンプレートを読み込んで表示する仕組み。テンプレートの共通部分をSSIで表示。
SSIが処理されないらしいので。

//テンプレートファイル  tpl.html
<html>
  <body>
    <!--#include virtual="file.txt" -->
  <body>
</html>

とかテンプレート側に書いたら、PHPでファイルを読み込んで置換する。
※追記
複数のマッチングに対応できてなかったので修正。


$tpl = "tpl.html";
preg_match_all("/(<!--#include virtual=\")([a-z0-9\_\.\/^\"]+)(\" -->)/i",
                           $tpl,$array,PREG_SET_ORDER);

chdir("templates");
  //カレントディレクトリ移動
foreach ($array as $match) {
  $tpl=ereg_replace("(<!--#include virtual=\"".$match[2]."\" -->)",
                                 file_get_contents($match[2]),$tpl); 
   //テンプレートファイルからの相対パスで記述
}
chdir("../");
  //カレントディレクトリ移動

もっとスマートな方法は無いもんか。
SSIが普通に使えればいいんだけどな。

ラベル: ,


 

PHP+MySQL+UTF-8で文字化け対策

自分は遭遇した事無いけど、今後の参考に。
PHPの内部処理の文字コードがEUCベースな為、UTF-8で作っていくとフォーム値が文字化けしてしまう事があるらしい。
結構多いトラブルの模様。
解決策としては、内部処理の文字コードをUTF-8に変更してから受け取る様にすると良い。

自分の経験で悩まされたのは、DBの文字化け
DBを一から構築する場合は最初からUTF-8で作っていけば良いけど、サーバの移転だったり既存のデータを使ったプログラムを組みときは文字化けが大変。EUC-JPが多い。
その時は以下のコードで文字コードを指定したクエリを発行して乗り越えられた。

<?
mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");

$db=mysql_connect("DBサーバ名","接続ID","接続パスワード");
mysql_query("SET NAMES utf8",$db); //クエリの文字コードを設定
mysql_select_db("DB名");
?>
yohgaki's blog
SET NAMESは禁止
MySQLには文字エンコーディングを変更する「SET NAMES」SQL文が用意されています。(PostgreSQLも同様のSQL文、SET CLIENT_ENCODINGがあります)この機能はSQLコンソールからは使ってよい機能ですが、アプリケーションからは使ってはならない機能です。 SQLインジェクションに脆弱になる場合があります。
(略) ストアドプロシージャだけ使っていれば安全ですが、アプリケーションからDBMSの文字エンコーディングを設定する場合、SQL文ではなく必ず文字エンコーディング設定APIを利用するよう紹介しなければならないです。
(略) 脆弱性の説明は面倒ですが注意事項は簡単です。「DBMSをアプリケーションから利用する場合、文字エンコーディング設定は必ずAPIを利用する」つまり「SET NAMES(SET CLIENT_ENCODING等も)は禁止」です。

"SET NAMES"で文字エンコーディングを指定している箇所はすべてmysql_set_charset()関数を利用するように書き換えた方が良いらしい。

<?
mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");

$db=mysql_connect("DBサーバ名","接続ID","接続パスワード");
mysqli_set_charset($db, "utf8") //クエリの文字コードを設定
mysql_select_db("DB名");
?>
mysqli::set_charset - PHPマニュアル

ただmysqli_set_charset()関数はPHP 5.2以降、MySQL 5.0.7以降でないと使えないようです。※こちらによるとMySQL 4.x系でも利用可能らしい

さらに悩ませる記事がありました。

SET NAMESは禁止?

日本語以外の記事では、「SET NAMESを使ってはいけない」とまで書いている記事が見つからなかったので、いまだすんなりと納得できていないのですが、今後、MySQL 4.1以上を入れた共有サーバなんかではどうすればいいんでしょうか…。

“SET NAMES sjs”に問題がある、という記事は下記にありました。

t_komuraの日記
addslashes() による SQL 文字列のエスケープ回避問題

hoshikuzu | star_dust の書斎
■PHP 利用時に Shift_JIS で addslashes() によるエスケープ処理に SQL インジェクション可能な穴

“mysql_real_escape_string()でもSET NAMES sjis;等を実行した後に使うと2バイト目の0x5C文字がエスケープされないようです。”

とりあえずmysqli_set_charset()関数が使える場合は良いとして、それ以前のサーバではどうするべきなんでしょうか。

ラベル: , , ,


2008年1月17日木曜日

 

TumblrのようなChyrpインストール

巷で話題のTumblr。

なつみかん@はてな
Tumblr はじめてガイド

TumblrはWebスクラップ帳です。はてブなどのSBM(ソーシャルブックマーク)にも似ていますが、SBMに比べると
  • 画像、動画を直接貼れる
  • 記事の中の文章を引用して貼れる
  • ブログのように自分で文章を書く事もできる
  • 自分のTwitterやブログやSBMのログを集約しておく事もできる
という点が優れています。(略)基本的にはただひたすら情報をクリップして積み重ねていくような感じですが、自分の書いた物を集約しておいたり、普通に日記として使う人もいたりと使い方は様々です。

写真と一言日記のシンプルなブログのような、ミニブログのような。
そういうのを実現するエンジン・Chyrp。インストール法。 Chyrpって?

もしChyrpを使ってみようと思うのなら、もう少し待った方が好いかも知れません。 次のv.1.0.4から少し仕様が変わり、v.1.0.3のバグも多数修正されるようです。フォーラムでもプラグインの作成を待ってもらう旨の作者さんの投稿がありました(今は削除されて無いようですが)。

[r]

  1. データベースを作成(MySQL4.0系での動作は保証外)
  2. Chyrpからファイルをダウンロード
    Chyrp: Download[Download v.1.0.3]
  3. ファイルを解凍しアップロード(フォルダ名:chyrp)
  4. 「chyrp」以下の「chyrp.htaccess」を「.htaccess」にリネーム
  5. 「includes」フォルダ内の「config.php.stock」を「config.php」にリネームし、パーミッションを777に変更
  6. 同じく「includes」フォルダ内の「database.php.stock」を「database.php」にリネームし、パーミッションを777に変更
  7. 「upload」フォルダのパーミッションを777に変更(写真などがアップされる)
  8. ※MySQL4.0系の場合のみ
    • install.phpの中のテーブル作成のコードを探す (59行目~)
    • クエリの"default charset=utf8"を消す
  9. ブラウザから「http://ホームページアドレス/install.php」のインストール画面にアクセス
  10. [Languge Select]のステップで[On to Step1]をクリック(localeは"English(US)"しかない)
  11. [Database Setup]で内容を入力し、[On to Step2]をクリック
    • Host…localhostのまま
    • Username…データベースのユーザーネームを入力
    • Password…データベースのパスワードを入力
    • Database…データベース名を入力
    • Table prefix…データベースの接頭語(よく解らなければそのままで)
  12. [Website Setup]を設定し、[Time for the final step]をクリックします。
    • Website URL…ホームページのURL
    • siteName…サイト名を入力
    • Description…サイト概要を入力
    • What time is it?…現在時刻(そのままで)
  13. [Admin Account]の設定、管理者のアカウントとパスワードを入力し、[All done!]をクリック
    • Username…管理者のアカウントを入力
    • password…管理者ログイン用のパスワードを入力
    • password(again)…もう一度パスワードを入力
    • E-mailAddress…メールアドレスを入力
  14. インストール完了
    [Take me to my site!]をクリック
    (install.phpは削除する)
  15. 表示を確認
似たようなソフトに「gelato」というソフトもあるのですが、個人的には「Chyrp」の方がインストールが簡単に感じました。

TumblrっぽいChyrpをインストールしてみた

Chyrpを触ってみた感想

日本語化ファイルを作成してくださった方々。

ブロックワークス
Chyrpの日本語用言語ファイルを作ってみた
[r]
Chyrp v.1.0.3 ja_JP


2008年1月9日水曜日

 

【PHP】携帯サイトからデータベースにアクセスする【文字コード】

PHP+MySQLでサイトを構築。
一般用の公開ページとユーザ用の編集ページがある仕組み。

普通にUTF-8でDBを構築。携帯用のサイトも作れって事で、Shift-JISが標準な携帯サイトUTF-8でしかテンプレートを作れないSmartyで四苦八苦。
Smartyを使ってUTF-8で作成し、表示直前にShift-JISにエンコードという方法で解決。(参照: Smartyはじめました!2007年12月28日エントリ)

携帯からも編集させろと完成間際に言われ、Shift-JISからUTF-8に変換してからSQLクエリを発効すればいいかと思ったらauだけ文字化け

調べると、携帯用のDBはShift-JISが無難らしいがPC兼用だしUTF-8でほとんど出来てるので変更は不可。
auはフォームを送るとき、action属性に必ず「x-up-destcharset=17」(例:index.php?x-up-destcharset=17&page=1)というのがつくとか、サーバで勝手にエンコードするので初期設定を変える必要が有るとか。
解決策が見つからず、内部エンコードとか怪しいところを調べたが不明。

auのフォーム値は強制Shift-JISとあったが、何故かPOSTの値がASCIIコードで送られている。 文字化けだと思ってた文字列がURLエンコード値だったのでPOST値をurldecode()関数でデコードするとShift-JISで文字化け解消
さらにUTF-8に変換してDBに渡す事でおそらく解決。

昔、携帯専用サイトを作ったときの文字化けは以下のコードで解決した。


$interenc = mb_internal_encoding();
$inputenc = mb_convert_variables($interenc, "ASCII,UTF-8,SJIS-win", $str);

ラベル: , ,


2008年1月8日火曜日

 

ディレクトリのファイルを一覧表示

ディレクトリツリー
PHPの基礎体力

■ ディレクトリデータモデル
配列は、「添え字 => 値」という関係になっていて、どのようなデータ型でも入れることが出来ます。あるディレクトリ内部を獲得しようとした時、「ディレクトリ」であれば「キー」に「ディレクトリ名」を格納し、「値」には下位の内容を配列で格納します。
「ファイル」ならば「キー」に「ファイル名」を格納し、値には「パス」を格納することにします。
以下は、ディレクトリを配列に格納した時のイメージ図です。
ディレクトリ( ./sample )内を配列に格納した時のデータモデル図
<? Array ( [edithead.php] => ./sumple/edithead.php [conf.txt] => ./sumple/conf.txt [file.html] => ./sumple/file.html [strings.html] => ./sumple/strings.html [data] => Array ( [template] => Array ( [file.data] => ./sumple/data/template/file.data [file.data.bak] => ./sumple/data/template/file.data.bak [readme.txt] => ./sumple/data/template/readme.txt ) [log.txt] => ./sumple/data/log.txt ) ) ?>
ディレクト内のファイル名を獲得するには、先ず opendir() でディレクトリのハンドルを獲得後、readdir() で次々とファイル名を読み出し、全て読み終えたところで、closedir() でディレクトリハンドルを閉じるという流れになります。
ディレクトリ内のファイル一覧を配列で獲得する関数( function grtdirtree() )
< //***************************************************** // function getdirtree( $dir ) //  指定したディレクトリ以下のファイル一覧を獲得します。 //----------------------------------------------------- // 引 数:ディレクトリを示す文字列 // 戻り値:ファイル一覧を格納した配列 // 注 意:$dir は、スクリプトから見た相対パスを指定します。 //***************************************************** function getdirtree( $dir ) { if( !is_dir( $dir ) ) // ディレクトリでなければ false を返す return false; $tree = array(); // 戻り値用の配列 if( $handle = opendir( $dir ) ) { while ( false !== $file = readdir( $handle ) ) { // 自分自身と上位階層のディレクトリを除外 if( $file != "." && $file != ".." ) { if( is_dir( $dir."/".$file ) ) // ディレクトリならば再帰呼出 $tree[ $file ] = getdirtree( $dir."/".$file ); else // ファイルならばパスを格納 $tree[ $file ] = $dir."/".$file; } } closedir( $handle ); uasort( $tree, "strcmp" ); // uasort() でないと添え字が失われます } return $tree; } ?>

ディレクトリのファイルを一覧表示
eWeb

ディレクトリのファイルを一覧表示 ディレクトリ内のファイルを一覧表示します。あわせて、ファイルサイズや最終更新日も表示することが可能です。

<?php
$rep = 1; // 最終更新日(表示=1 非表示=0)
$sze = 1; // ファイルサイズ(表示=1 非表示=0)
$lst = "./list"; // 表示するリストの名前(パス)

$drc=dir($lst);
print("<OL>");
while($fl=$drc->read()) {
  $lfl = $lst."/".$fl;
  $din = pathinfo($lfl);
  if(is_dir($lfl) && ($fl!=".." && $fl!=".")){
    print("<LI>".$din["basename"]."<FONT size='-1'> (ディレクトリ)</FONT></LI>");
  } else if($fl!=".." && $fl!=".") {
    print("<LI>");
    print("<a href=".$lst."/".$fl.">".$fl."</a>");
    // ファイル更新日
    if($rep == 1 || $sze == 1) print("<FONT size='-1'> (");
    if($rep == 1) echo date("m/d",filemtime($lfl));
    if($rep == 1 && $sze == 1) print(", ");
    // ファイルサイズ
    if($sze == 1) echo round(filesize($lfl)/1024)."KB";
    if($rep == 1 || $sze == 1) print(")</FONT> ");
    print("</LI>");
  }
}
print("</OL>");
$drc->close();
?>
実行結果
  1. dummy1.txt (02/18, 0KB)
  2. dummy2.txt (02/18, 0KB)
  3. dummy3.txt (02/18, 0KB)
  4. dummy4.txt (02/18, 0KB)
  5. dummy5.txt (02/18, 0KB)
  6. sampleimage01.gif (02/18, 1KB)
  7. sampleimage02.gif (02/18, 1KB)
  8. sampleimage03.gif (02/18, 1KB)
  9. sampleimage04.gif (02/18, 1KB)
  10. sampleimage05.gif (02/18, 1KB)
  11. dummyDir1 (ディレクトリ)
  12. sampleDir1 (ディレクトリ)
※ファイルへのリンクは削除して有ります
参考
PHPの基礎体力
http://www.sound-uz.jp/php/
eWeb
ホームページ作成支援,Web Design
http://www.eweb-design.com/

ラベル: ,


 

【PHP】ディレクトリ内を検索して一覧情報を取得する【scandir()関数】

【PHP TIPS】 54. 再帰関数を使ってみよう

再帰関数は、関数の中でその関数自身を呼び出す、ということを行っている関数です。将棋やチェスのようなゲームや、パズルを解くようなプログラムではよく使われ、プログラムをとてもシンプルに、見通しよく記述することができます。今回は、そんな再帰関数をPHPで使った例をご紹介します。

PHPでゲームを作る、というようなことはまずないと思うので、使いどころはかなり限られてしまうのですが、それでも便利に使える場面がないわけではありません。ここではディレクトリ内のファイルをチェックし、そのディレクトリ内に含まれるファイルサイズの合計を求めるプログラムを作ってみます。

ディレクトリに含まれるのが全てファイルなら、再帰関数でなくても大丈夫ですが、ディレクトリ内が階層になっている場合は再帰関数が威力を発揮します。

<?php
//PHP4の場合、scandir関数がないので実装しておきます。
if (!function_exists(scandir)) {
  function scandir($dir_name, $order = '') {
    $dh = opendir($dir_name);
    while ( ($filename = readdir($dh)) !== false) {
      $file_list[] = $filename;
    }

    if ($order) {
      rsort($file_list);
    } else {
      sort($file_list);
    }
    return $file_list;
  }
}

//引数 $pathにはディレクトリ、またはファイルの絶対パスを指定。
function getDirSize($path) {
  $total_size = 0;

  //指定したのがファイルだった場合はサイズを返して終了。
  if (is_file($path)) {
    return filesize($path);

  } elseif (is_dir($path)) {
    $basename = basename($path);

    //カレントディレクトリと上位ディレクトリを指している場合はここで終了。
    if ($basename == '.' || $basename == '..') {
      return 0;
    }

    //ディレクトリ内のファイル一覧を入手。
    $file_list = scandir($path);

    foreach ($file_list as $file) {
      //ディレクトリ内の各ファイルを引数にして、自分自身を呼び出す。
      $total_size += getDirSize($path .'/'. $file);
    }
    return $total_size;

  } else {
    return 0;
  }
}


//関数を実行。
echo getDirsize('/home/asial');

?>

これだけで、指定したディレクトリ内のファイルサイズを求めることができます。

ただ、注意しないといけない点もあります。少し間違えたり、思いがけない例外があった場合、無限ループに陥ってしまうことがあります。上記のプログラムの場合、basename関数を使ってチェックを行わないと無限ループになります。また、指定したディレクトリ内にシンボリックリンクがある時も無限ループになってしまう場合があるので気をつけて下さい。

【PHP TIPS】 54. 再帰関数を使ってみよう

参考
PHPマニュアル
PHP マニュアル翻訳プロジェクト
http://manual.jpnote.net/php/function.scandir.html
PHPプロ!
PHPのコミュニティ ポータルサイト
http://www.phppro.jp/phpmanual/php/function.scandir.html

ラベル: , ,


2008年1月3日木曜日

 

フォーム要素でHTMLタグを許可したいときのXSS・JavaScript対策

HTML Purifier
デモペ-ジ
インストール方法

デモページはテキストエリアにウェブページのソース(HTML,CSS,JavaScript混合のテキスト)を入力して「Submit」。デフォルトではJavaScriptだけ(<script>やonClickなど)が取り除かれる。
HTMLタグを個別に許可したい場合は、右側「HTML-> Null/Disabled」のチェックを外して、Allowedに許可タグを入力。
形式は以下のようにカンマ区切りで、[]内に許可する属性を指定。


a[href|title],p[id|class],b,i,ul,li

実際にプログラムで使う場合。
ダウンロードしたファイルをサーバにアップし、以下のコードで呼び出す。
例はアップしたフォルダを「htmlpurifier」とした。
「htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/」内にあるディレクトリの属性を全て書き込み可能(0777or0707)にしておく。


require_once 'htmlpurifier/library/HTMLPurifier.auto.php';

使い方は以下。$pure_htmlにはJavaScriptが取り除かれたhtmlテキストが入る。


$config = HTMLPurifier_Config::createDefault();

$purifier = new HTMLPurifier($config);

$html = mb_convert_encoding(file_get_contents("index.html"),"UTF-8");

$pure_html = $purifier-> purify($html);

個別でタグを指定する場合は以下。


$purifier = new HTMLPurifier(array(
            'HTML.AllowedElements' => array('b', 'i', 'p', 'a','ul','li'),
            'HTML.AllowedAttributes' => array('a.href', '*.id'),
        ));
$pure_html = $purifier->purify($html);

スタイル属性での@importやbackground-urlの値がURLだと消去される模様。

参考としては、「docs/examples/basic.php」が一番シンプルな雛型。
使い方や他の機能に関しては「tests/」内の「HTMLPurifierTest.php」「index.php」のテスト用クラスを参考。

ラベル: , , ,


This page is powered by Blogger. Isn't yours?

登録 投稿 [Atom]

Google