Updated: 2006.12.04
Hit:
« 2005年06月 | index | 2006年04月 »

Navigation of sieg

Index
Information
サイトマップ


最近のエントリー

インストール型ブログ
セキュリティコード
GoogleSitemapsジェネレータ
サイト探索


Link

ActivePerl
Perlドキュメント(和訳)
Perlデータ構造
Apache JP
Apache 中核機能

ipodnanou_180-150.gif



関連用語 (e-Words)



Opera
rss1.0
rss2.0
atom0.3
BLOGinSPACE

ほっとけない 世界のまずしさ

Opera 9 - Your Web, Your Choice

クリエイティブ・コモンズ・ライセンス
クリエイティブ・コモンズ・ライセンス



2005年07月22日

インストール型ブログ


なるべくたくさんのサーバインストール型ブログを集めてみました

使用言語は、Perl、PHP、Pythonがあり
データベースは、MySQL、PostgreSQL、そしていらないものまでありました
いらないものはたぶん、テキスト保存かPerl用のデータベースを使っていると見られます
利用ライセンス形態もさまざまで、GPL(Gnu Open Sorce)、BSD License、
商用は有料だが非商用は無料、そして制限なしというところまであります
また、どこをどう探してもそれらの記述のないサイトもありましたので「制限なし(?)」で示しました

探せばたぶんまだまだあると思うので、まずはパート1ということで
以下18種類を並べてあります


Movable Type(ムーバブルタイプ)
シックス・アパート社
www.movabletype.jp (日本)
www.movabletype.org (米国)
ライセンス 非商用利用は無料、商用利用は有料
DB 不要(MySQL利用可)
言語 Perl

Nucleus(ニュークリアス)
The Nucleus Group
japan.nucleuscms.org (日本)
nucleuscms.org (米国)
ライセンス フリー (GPL)
DB MySQL
言語 PHP

tDiary www.tdiary.org (日本)
ライセンス フリー (GPL)
DB MySQL利用可
言語 Ruby

GsBlog
Web Application Factory
www.waf.jp/contents/download/gsblog (日本)
ライセンス 非商用利用は無料、商用利用は有料
DB MySQL
言語 PHP

P_BLOG
P_BLOG Proj
pbx.homeunix.org/p_blog (日本)
ライセンス フリー (GPL)
DB MySQL必須
言語 PHP

華式(Kshiki)
流之進
ryunosin.hp.infoseek.co.jp/KshikiSetup.html (日本)
ライセンス フリー (GPL)
DB 不要
言語 Perl

Blogn(ぶろぐん)
R・ONEコンピューター
www.blogn.org (日本)
ライセンス 非商用利用は無料、商用利用は有料
DB 不要(MySQL利用可)
言語 PHP

rNote
Woody-Rinn
rinn.e-site.jp/rnote (日本)
ライセンス 使用制限なし
DB 不要
言語 PHP

Serene Bach
sb開発研究所
serennz.cool.ne.jp/sblog/ (日本)
ライセンス 非商用利用は無料、商用利用は有料
DB 不要
言語 Perl

COREBlog
Webcore Corp
coreblog.org (日本)
ライセンス 使用制限なし(?)
DB 不要
言語 Python(Zope)

blosxom
Rael Dornfest
www.blosxom.com
ライセンス 使用制限なし
DB 不要
言語 PHP or Perl

bBlog
Eaden McKee
www.bblog.com
ライセンス フリー (GPL)
DB MySQL
言語 PHP

WordPress wordpress.org
ライセンス フリー (GPL)
DB MySQL
言語 PHP

Serendipity Blog
s9y
www.s9y.org
ライセンス フリー (BSD License)
DB MySQL or PostgreSQL
言語 PHP

teeter totter
solo.design
solodesign.jp/tt
ライセンス 非商用利用は無料、商用利用は有料
DB 不要
言語 Perl

stereolog
マツオ (tar100mg)
tar100mg.com/stereolog
ライセンス 使用制限なし
DB 不要
言語 PHP

PwBlog
株式会社CATWALK
www.pwblog.com
ライセンス 非商用利用は無料、商用利用は有料
DB PostgreSQL
言語 Perl

lily www.mikihoshi.com/lily
ライセンス フリー (GPL)
DB 不要
言語 Ruby
投稿者 edams : 18:56 | コメント (0) | トラックバック | ▲

2005年07月17日

セキュリティコード


登録認証時のセキュリティコード

登録するときに、画像の文字を入力してくださいっていうのがあります
あれは、自動登録などを防ぐためにあるそうです
「submission code」(サブミッション・コード)とも言うそうです
いまひとつ仕組みがわからないので、自分で考えてみることにしました

約束事として、
HTMLファイルのソースを直接見られても、セキュリティコードがわかってはならない
暗号化するにしても、方法がわかってはならない


[1] まず最初に、かなり回りくどい方法から
これは、HTML,JavaScript,Flash,CGIをつかいます
フローとしては
  1. HTMLファイルを表示
  2. その際JavaScriptで乱数を生成
  3. 生成された乱数をFlashへの引数と次画面(登録CGI)へのhiddenパラメータとして渡す
  4. Flashの方は、受け取った乱数を書き込み用のCGIへ渡し、戻り値として文字列を受け取り表示する
  5. 書き込み用のCGIでは受け取った乱数と更に表示用に生成した6桁の乱数文字列、現在の日付をファイルに書き出し、ここで表示用に生成した6桁の文字列を返す
  6. ユーザはFlashで書き出された文字列を読み入力フィールドに書き送信
  7. 登録CGIでは、受け取った乱数とセキュリティコード、日付の差をファイルと比較、その他の入力項目も確認して真偽を決定
  8. 真なら更に現在の時間フィールドを追加してファイルに保存 (日付超過データを削除)
  9. 真ならユーザに登録内容を確認させて、アクティベーション用のURLを書いてメール送信
  10. アクティベーションURL用のCGIで正規のコードを受け取った時点で先ほどのデータを削除して、ユーザ登録をする
この方法の利点は
 ・HTMLでの表示
 ・このHTMLで見られる乱数は、表示されるセキュリティーコードとはまったく無関係である

欠点として
 ・JavaScriptとFlashが必須
 ・作る側は、かなりめんどうなことになる


[2] 上記のものを改良
これは、Flashを使わずGIFアニメーションを生成する(gifcat.pl使用)
フローはほぼ同じ
Flashの部分をなくして、<img>タグでCGIに乱数を渡す

この方法の利点は
 ・Flashがいらなくなる

欠点として
 ・ばらばらのGIF画像を大量に作っておく必要がある
 ・出かたが変 (gifcat.plの特徴)

考察の余地
Image::Mgickをつかって一つのGIF画像を作成するという手法がある


[3] 更に改良
HTML表示ではなくCGIによる表示 (普通はこっちかも)
これもJavaScript部分をCGIで書き出すだけで、Flashなら[1]とほぼ同じ、GIF画像なら[2]とほぼ同じ

この方法の利点は
JavaScriptがいらなくなる


では、[1]から検証
HTML,JavaScript,Flash,CGIを使ったサンプル
以下のファイル(4+1)をまとめたものをダウンロードできます
File: secur_code.zip


入力用のHTML[index.html]

Code: download

  1. <h1>セキュリティコード認証のテスト</h1>
  2.  
  3. <form action="check.cgi" method="POST">
  4. <fieldset><legend>Regist Form</legend><br />
  5. <h2>登録するユーザ名を入力してください(半角英数字20文字以内)</h2>
  6. Name : <input type="text" name="name" size="20"><br /><br />
  7. <h2>右側の画像に表示されている、文字列を入力してください</h2>
  8. Code : <input type="text" name="code" size="10">
  9. <script>
  10.  var rand = Math.floor(Math.random()*10000000000);
  11.  document.write('<OBJECT classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '+
  12.  'codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" '+
  13.  'width="90" height="25" id="code.swf" align="middle"><param name="allowScriptAccess" value="sameDomain">'+
  14.  '<param name="quality" value="high"><param name="bgcolor" value="#000000">'+
  15.  '<param name="movie" value="code.swf"><param name="FlashVars" value="code=' + rand +'">'+
  16.  '<embed src="code.swf" quality="high" bgcolor="#000000" width="90" height="25"'+
  17.  ' name="code.swf" align="middle" allowScriptAccess="sameDomain" FlashVars="code=' + rand + '" '+
  18.  'type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer">'+
  19.  '</object><input type="hidden" name="ccode" value="'+rand+'">');
  20. </script>
  21. <noscript><h2>JavaScriptを有効にしてください</h2></noscript><br /><p><input type="submit" value="送 信"></p>
  22. </fieldset></form>
  23.  
  24. <h3>* 画像が見えにくい場合は、<a href="./">読み込みなおして</a>ください</h3>
  25. <h3>* 送信後、確認画面を表示します</h3>
ほとんどがFlash(code.swf)を引数つきで呼び出すだけのタグです

10行目でJavaScriptで10桁の乱数を生成して(rand)
それを、15行目と17行目でFlashへの引数として書き出しています
更に、19行目ではhiddenフォームとして次画面のCGIへ渡すよう書き出しています
21行目はJavaScriptが使えない場合の警告です



Flash[code.swf]内のAction Script

Code: download

  1. cginame = "ccode.cgi?code=";
  2. inval = _root.code;
  3. lv = new LoadVars();
  4. lv.onLoad = function() {
  5. tfCount.text = this.secure_num;
  6. };
  7. lv.load(cginame + inval);
1行目で、書き込み用のCGIまでのパスを指定
2行目では、先ほどJavaScriptで書き出した引数を取得
5行目で、書き込み用CGIからの戻り値を表示 (secure_numは書き込み用CGIからの戻り値パラメータ)
7行目で、書き込み用のCGIへ引数を渡しています

Flashの作り方は、リンク集を参考にしてください
File: code.fla は、「Macromedia Flash MX 2004」で作成しています


Made with Macromedia Flash MX



書き込み用CGI [ccode.cgi]

Code: download

  1. use CGI  qw(:standard);
  2.  
  3. $code_file = 'code.txt';
  4. $limit = 7200;
  5. $incode = (param('code') =~ /\d+/) ? param('code') : die;
  6. $rand_code = sprintf("%d%d%d%d%d", int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)));
  7. $time = time;
  8.  
  9. open(CODE, "+< $code_file") or open(CODE, ">$code_file");
  10. flock(CODE,2);
  11. while(<CODE>) {
  12.  $date = (split("\t",$_))[2];
  13.  chomp($date);
  14.  next if (($time-$date)>$limit);
  15.  push @out, $_;
  16. }
  17.  
  18. push @out, "$incode\t$rand_code\t$time\n";
  19. seek(CODE, 0, 0);
  20. print CODE @out;
  21. truncate(CODE, tell(CODE));
  22. close CODE;
  23.  
  24. print "Content-type: text/plain\n\nsecure_num=$rand_code";
今回表示する文字列は、数字に限定しました(0〜9)

3行目で、データ保存ファイル名を指定
4行目で、有効期限を秒数で指定(ここでは2時間以内)
5行目では、JavaScript→Flashの順で経由してきた乱数を取得しています
6行目で、Flashで表示用の5桁の乱数を生成
7行目は、現在の日付(エポックタイム)
9〜16行目までで、新規書き込みと 有効期限が過ぎたデータを削除
18行目での、データの並び順は
    1. JavaScriptで生成された乱数
    2. 表示用に生成した乱数文字列(5桁)
    3. 現在の日付(エポックタイム)
24行目で、Flashへの戻り値として、secure_num=表示用文字列 を返す



入力確認CGI [check.cgi]

Code: download

  1. use CGI  qw(:standard);
  2.  
  3. $code_file = 'code.txt';
  4. $limit = 7200;
  5. $re_date = time;
  6. $que = param('que');
  7. $in{code} = param('code');
  8. $in{ccode} = param('ccode');
  9. $in{name} = param('name');
  10. $secur = sprintf("%d%d%d%d%d", int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)));
  11.  
  12. open(FH, "+< $code_file") or die "Can't open $code_file: $!";
  13. flock(FH,2);
  14. while(<FH>) {
  15.  chomp;
  16.  my($ccode,$code,$date,$dmy) = split("\t");
  17.  if(($ccode eq $in{ccode}) && ($code eq $in{code}) && (($re_date-$date)<$limit)) {
  18.    push @out, qq($ccode\t$code\t$re_date\t$secur\n);
  19.    $flag = 1;
  20.    $ok_code = $code;
  21.    $save_rand = $ccode;
  22.    $save_time = $date;
  23.    $now = $re_date;
  24.  }
  25.  elsif(($re_date-$date)>$limit) {
  26.   next;
  27.  }
  28.  else {
  29.   $flag = 2 if ($ccode eq $in{ccode});
  30.   push @out, "$_\n";
  31.  }
  32. }
  33. seek(FH,0,0);
  34. print FH @out;
  35. truncate(FH, tell(FH));
  36. close(FH);
  37.  
  38. if($flag == 1) {
  39.  $sec_code = qq(セキュリティーコードが一致しました) }
  40. elsif($flag == 2) {
  41.  $sec_code = qq(セキュリティーコードが一致しません) }
  42. else {
  43.  $sec_code = qq(セキュリティコードの有効期限が過ぎているか無効です) }
  44.  
  45.  print <<HTML;
  46. Content-type: text/html\n\n
  47. <html><head>
  48. <title>test - check</title></head><body>
  49. <h1>セキュリティコード認証のテスト - 確認</h1>
  50. <br />
  51. <h2>$sec_code</h2>
  52. <table width="400" border="1" cellspacing="0" cellpadding="3">
  53. <tr><td>ユーザ名</td><td>$in{name}</td></tr>
  54. <tr><td class="col">保存されているセキュリティーコード</td><td class="col">$in{code}</td></tr>
  55. <tr><td>表示されたセキュリティコード</td><td>$ok_code</td></tr>
  56. <tr><td class="col">保存されている乱数</td><td class="col">$save_rand</td></tr>
  57. <tr><td>JavaScriptで生成された乱数</td><td>$in{ccode}</td></tr>
  58. <tr><td class="col">保存されていた日付</td><td class="col">$save_time</td></tr>
  59. <tr><td>現在の日付(書き換えた日付)</td><td>$now</td></tr>
  60. </table>
  61. <br />
  62. <h3>* 通常はここで確認ボタンを表示してメール送信画面に進みますが省略</h3>
  63. <br />
  64. <p><a href="javascript:window.close()">閉じる</a></p>
  65. </body></html>
  66. HTML
3行目は、データ保存ファイル名を指定
4行目で、有効期限を秒数で指定します(ここでは2時間以内)
5行目、有効期限の比較用に現在の日付を取得
6〜9行目では、HTMLからの引数を取得しています
10行目で、アクティベーション用に新たに追加する乱数生成
17行目で、セキュリティコードと乱数、有効期限を確認
19行目の$flagは、表示用の確認フラグです (コード、乱数、有効期限ともに真)
25,26行目の処理は、有効期限切れを削除するためです
29行目、表示用の確認フラグで入力ミスを検出(コードは偽だが、乱数は真)
38〜43行目までで、フラグによる可否表示情報を作成

今回は、これらの情報をHTMLファイルとして確認用に書き出しています


投稿者 edams : 01:19 | コメント (0) | トラックバック | ▲

2005年07月10日

GoogleSitemapsジェネレータ


前回のサイト探索からの続きで
Google Sitemaps用のXMLファイルを出力するスクリプトを作ってみた(コマンド編)
強調されている行番号は前回(サイト探索)からの変更点

Code: download

  1. use LWP::Simple qw(get head);
  2. use HTML::LinkExtor;
  3. use strict;
  4.  
  5. my(%seen,%mod_time,%out,$site,$top_url,$freq,$priority);
  6. $freq = 'weekly';
  7. $priority = '1.0';
  8. $top_url = 'http://sieg.xeong.com/';
  9. $top_url = "http://$top_url" unless $top_url =~ /^https?\b/;
  10. ($site = $top_url) =~ s/^(http:\/\/.+\/).*$/$1/;
  11. $site .= "/" unless ($site =~ /\/$/);
  12.  
  13. &print_xml_head;
  14. linker($top_url);
  15. &print_xml_foot;
  16.  
  17. sub linker {
  18.  my $base_url = shift;
  19.  my $parser = HTML::LinkExtor->new(undef, $base_url);
  20.  $parser->parse(get($base_url))->eof;
  21.  my @links = $parser->links;
  22.  for my $linkarray (@links) {
  23.   my @element = @$linkarray;
  24.   my $elt_type = shift @element;
  25.   while(@element) {
  26.    my ($attr_name, $attr_value) = splice(@element, 0,2);
  27.    if( $attr_name eq "href" && $attr_value->scheme =~ /\b(https?)\b/ && $attr_value =~ /^$site/
  28.     && ($attr_value =~ /\.xml?$/i or $attr_value =~ /\.s?html?$/i or $attr_value =~ /\.php.*$/i or $attr_value =~ /\.cgi.*$/i)
  29.    ){
  30.     $attr_value =~ s/^(.+)#.*$/$1/;
  31.     next if(defined $seen{$attr_value});
  32.     my @heads = LWP::Simple::head($attr_value);
  33.     if(@heads) {
  34.      $seen{$attr_value}++;
  35.      my @date = $heads[2] ? gmtime($heads[2]) : gmtime(time);
  36.      $mod_time{$attr_value} = sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", $date[5]+1900, $date[4]+1, @date[3,2,1,0]);
  37.     }
  38.    }
  39.   }
  40.  }
  41.  
  42.  for (sort keys %seen) {
  43.   my $mod = $mod_time{$_};
  44.   s/^(.+\.cgi).*$/$1/i;
  45.   s/^(.+\.php).*$/$1/i;
  46.   if(defined $out{$_}) {
  47.    next;
  48.   } else {
  49.    $out{$_} = 'true';
  50.    print_xml($_,$mod);
  51.    linker($_);
  52.   }
  53.  }
  54. }
  55.  
  56. sub print_xml_head {
  57.  my %in_url = @_;
  58.  my @date = gmtime(time);
  59.  my $mod_time = sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", $date[5]+1900, $date[4]+1, @date[3,2,1,0]);
  60.  print <<XML;
  61. <?xml version="1.0" encoding="UTF-8"?>
  62. <urlset xmlns="http://www.google.com/schemas/sitemap/0.84"
  63. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  64. xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84
  65. http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">\n
  66. <url>
  67. <loc>$top_url</loc>
  68. <lastmod>$mod_time</lastmod>
  69. <changefreq>$freq</changefreq>
  70. <priority>$priority</priority>
  71. </url>\n
  72. XML
  73. }
  74.  
  75. sub print_xml {
  76.  print qq(<url>\n<loc>$_[0]</loc>\n<lastmod>$_[1]</lastmod>\n</url>\n);
  77. }
  78.  
  79. sub print_xml_foot {
  80.  print qq(\n</urlset>\n);
  81. }

使い方
6行目で、内容の更新頻度("always", "hourly", "daily", "weekly", "monthly", "yearly", "never")を指定
7行目で、同じサイト内の他のページと比較した優先度(0.0〜1.0)
8行目で探索するURLを指定
Windowsではコマンドラインから、これを実行するとGooglSitemaps用のXMLを表示する

WindowsコマンドプロンプトでのXMLファイル(sitemap.xml)への出力例
perl -w xmlgen.pl > sitemap.xml

環境
以下のperlモジュールが必要
LWP::Simple
HTML::LinkExtor

参照
UTCタイムについて、W3CのDate and Time Formatsを参考にした
Link::Extorについては Perldoc と、河馬屋二千年堂さんの日本語訳を
Google Sitemapsについては、Google Sitemaps (BETA) HelpのUsing the Sitemap Generatorを参考にした

投稿者 edams : 17:01 | コメント (0) | トラックバック | ▲

2005年07月02日

サイト探索


Google Sitemaps ジェネレーターを作るにあたり、ネットワークから
サイト内のリンクをたどり、同一サイト内のURLを抽出するスクリプトを作ってみた

Code: download

  1. use LWP::Simple qw(get head);
  2. use HTML::LinkExtor;
  3. use strict;
  4.  
  5. my(%seen,%mod_time,%out,$site,$top_url);
  6. $top_url = 'http://sieg.xeong.com/';
  7. $top_url = "http://$top_url" unless $top_url =~ /^https?\b/;
  8. ($site = $top_url) =~ s/^(http:\/\/.+\/).*$/$1/;
  9. $site .= "/" unless ($site =~ /\/$/);
  10.  
  11. linker($top_url);
  12.  
  13. sub linker {
  14.  my $base_url = shift;
  15.  my $parser = HTML::LinkExtor->new(undef, $base_url);
  16.  $parser->parse(get($base_url))->eof;
  17.  my @links = $parser->links;
  18.  for my $linkarray (@links) {
  19.    my @element = @$linkarray;
  20.    my $elt_type = shift @element;
  21.    while(@element) {
  22.      my ($attr_name, $attr_value) = splice(@element, 0,2);
  23.      if(  $attr_name eq "href" && $attr_value->scheme =~ /\b(https?)\b/ && $attr_value =~ /^$site/){
  24.        #   && ($attr_value =~ /\.xml?$/i or $attr_value =~ /\.s?html?$/i or $attr_value =~ /\.php.*$/i or $attr_value =~ /\.cgi.*$/i)){
  25.        $attr_value =~ s/^(.+)#.*$/$1/;
  26.        next if(defined $seen{$attr_value});
  27.        my @heads = LWP::Simple::head($attr_value);
  28.        if(@heads) {
  29.          $seen{$attr_value}++;
  30.          my @date = $heads[2] ? gmtime($heads[2]) : gmtime(time);
  31.          $mod_time{$attr_value} = sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", $date[5]+1900, $date[4]+1, @date[3,2,1,0]);
  32.        }
  33.      }
  34.    }
  35.  }
  36.  
  37.  for (sort keys %seen) {
  38.    my $mod = $mod_time{$_};
  39. #    s/^(.+\.cgi).*$/$1/i;
  40. #    s/^(.+\.php).*$/$1/i;
  41.    if(defined $out{$_}) {
  42.      next;
  43.    } else {
  44.      $out{$_} = 'true';
  45.      print qq($_ - $mod\n);
  46.      linker($_);
  47.    }
  48.  }
  49. }

使い方
6行目で探索するURLを指定
Windowsではコマンドラインから、これを実行するとリンクリストとUTC時間を表示する

Windowsコマンドプロンプトでのテキストファイル(link.txt)への出力例
perl -w linkgen.pl > link.txt


環境
以下のperlモジュールが必要
LWP::Simple
HTML::LinkExtor

解説
6行目: $top_urlに探索したいサイトのトップページを指定する
以下9行目までは、URLの補間処理
11行目: サブルーチン linker 実行

linker:
15,16行でページ内のリンクリストを取得、このリストは17行目 @links に格納
23行目で href属性 内の http又はhttps で始まり、サイトの url を含むものだけに分類
24行目はコメントアウトしてあるが、はずすと xml,htm,html,shtm,shtml,php,cgi だけに絞り込める (その際23行目後ろの2文字は取り去ること)
25行目でページ内リンク(アンカー)を取り去る
26行目重複を確認(再帰しているのでこれを怠ると止まらなくなる)
27行目でヘッダ情報を取得
29行目も重複対策 (%seenに格納)
30行目は対象ページの最終更新日からGMTタイムを取得
31行目で整形して %mod_time に格納
38行目は、以下2行をコメントアウトした場合の対策としての位置
39,40行目は、コメントアウトしているがCGIとPHPへの変数を削除
以下4行は、更に重複を確認 (心配性です)
45行目で出力 形式は 完全URL - UTCタイム
46行目で再帰

注意
しつこいようだが再帰処理しているので、改変時には注意を
サイトの構成、ネットワークの状態にもよるが かなり時間がかかるはず
できるだけ、コメントアウトしているところを実行させるほうがいい
27行目: LWP::Simple::headとしているのはCGI.pmのheadとの名前衝突回避のため

参照
UTCタイムについて、W3CのDate and Time Formatsを参考にした
Link::Extorについては Perldoc と、河馬屋二千年堂さんの日本語訳を
LWP::Simple については言うまでもないだろう

方向性
これから、Google Sitemaps ジェネレーターを作っていこうと思っているわけで
とりあえずは、URLの抽出と ISO 8601形式の時間換算をやってみた
次は簡単 Google Sitemaps (BETA) Helpと
グーグル・サイトマップ(ベータ版)FAQとプロトコル全訳
を参考にXMLタグを組むだけ 今度はCGIにしようと思う

投稿者 edams : 03:37 | コメント (0) | トラックバック | ▲