三流君ASPで遊ぶ、失敗する
バックナンバー No.60 〜 No.64
<しつこい加筆解説、学習方法、拾ったサンプルソースをものにする方法>
こんにちは、三流プログラマーのKen3です。
前回のNo.59に文章を付け足しただけですが
学習方法、拾ったサンプルソースをものにする方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
として、再度追加発行します。
発行前にもっと内容、見たほうがよかったですね。
くだらない解説付のほうがいいのか?
それとも
マジメな解説がいいのか?
迷うところだけど。
基準として、
同じネタでも毒吐いてるのは、
http://www.ken3.org/guchi/
のプログラマー愚痴系で、
http://www.ken3.org/asp/
のASP系は、マジメに解説しようと思っているのですが、
同じ作者なので、時々、まざってしまうけど、ご勘弁を。
拾い読みして、何かの参考となれば幸いです。
/*
* 1.今回のキッカケ
*/
ASPでExcelの処理、ADO使ってごまかしたけど、
他に方法無いか?模索中・・・・
そしたら、マイクロソフトのHPから、おっ?と思うサンプルを拾う。
拾ったサンプルを自分のものにした、そんなストーリーを書きます。
元ネタは、ASPですが、他の言語でもやりかたは一緒だと思うので、
何かのきっかけとなれば、、、、
いつもの三流プログラマーの語りから、何かをつかんでくれれば幸いです。
/*
* 2.拾ったサンプル
*/
ASP Excel でいろいろと検索、巡回してました。
いろいろと出てきますねぇ、要望が多いのかなぁ。
私のつぶされそうなカスページにもポツポツ検索で来るし、
おっ、マイクロソフトのサンプルページかぁ、
よし、見てみるか。
※てな感じで、みなさんも必要なサンプルを探していると思います。
http://msdn.microsoft.com/library/en-us/dnwebteam/html/webteam07032000.asp
ちっ、ここも英語かよ、日本語のサンプルは無いの?
それとも日本語化される前に、ASP.NETになっちゃったの?
サンプル、見つかっても英語の時、ガックリ来ますよね。
なんて前置きは置いといて、
いつもの台詞で、英語読めないけどプログラムソースはなぜか読める
そんな三流プログラマーが下記のソースを拾ってきた。
※ページの下のほうに転がってました
あきらめないで、読めないのに軽く流し読みすると、
たまに自分の目にソースファイルが飛び込んでくる。
英語読めないけど(コメントやメッセージの意味は不明)
でも、VBAやASPの言語仕様は万国共通なので、
ソースファイルはなぜか不思議とある程度は読むことが出来ると思う。
<%@ language=vbscript %>
<%
response.buffer = true
response.ContentType = " application/vnd.ms-excel"
response.AddHeader " content-disposition" , " inline; filename=dynamic.xls"
response.write " <table width=200>"
response.write " <tr>"
for i = 1 to 4
response.write " <td width=40>"
response.write i + i
response.write " </td>"
next
response.write " <td width=40><b>=sum(A1:D1)</b></td>"
response.write " </tr>"
response.write " </table>"
response.flush
response.end
%>
response.writeで出力しているみたいだなぁ、
で、中身をざっと見てみると、
response.ContentType = " application/vnd.ms-excel"
response.AddHeader " content-disposition" , " inline; filename=dynamic.xls"
とExcel処理の匂いがプンプン。
※夏の女性の匂いに引き付けられないで、
サンプルの匂いに魅かれてちゃダメだよ。
ここで、私がもしかしたら使えるのかも?と思ったのが、
response.write " <td width=40><b>=sum(A1:D1)</b></td>"
と、セルの集計関数の=Sumを使っている場所。
データだけならCSV経由でサーバーから落として、
あと好きなように加工してね、、とやるんだけど、
もし=Sumなどワークシート関数使えるなら、
結果をASPからExcelで返す時、いろいろと使えるのでは?
で、上記ソースをまるごとコピーして、実行してみました。
http://www.ken3.org/cgi-bin/test/test059-1.asp
で実行できます。
すると、いつものxlsファイルを開く、保存の警告メッセージ。
ってことは、Excelのファイルとして認識?
※↑メッセージ画面
開くを選択して、開いてみると、=SUMの計算式が埋まっていた。
※↑開いたイメージ。
/*
* 3.拾ったサンプルを解析して自分のものにする
*/
さてと、そんな方法でExcelファイルを返すことが出来たので、
拾ったサンプルを自分のものにするために、
わからないことを探りますか。
ここが学生さんのレポートを丸写しで終わっていた課題と違うところかな
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
自分のものにしないとメルマガ読んでるだけじゃ意味無しですよ。
response.buffer = true
を調べると、
response.buffer = true
の時は、出力をバッファして、
response.flush 途中でバッファを出力
response.end ASPの処理を中止し、現在までの結果を返すのかぁ。
なるほどね。
関連項目として、今回出てこなかったけど、
response.clear
ってのがあって、バッファに格納された出力をクリアすることが出来ます。
このクリアを使って、エラーが発生したら、途中までの出力を消して、
エラーのメッセージ画面を表示することも出来そうです。
※また注意事項として、
response.buffer = trueは、<Html>などの出力の前に行うことです。
まぁ、出力のバッファだから、一番最初にやれってことね。
こんな、流れで、自分の知らない命令をヘルプで調べたり、
初めの調査はASP Excelだったのに、
芋ずる式にresponse.bufferを調べるようになり、自分のものになっていく。
また、自分で調べると関連項目、ここではサンプルに載っていなかった
response.clear
って出力をクリアする処理をついでに覚えて、
途中までの出力をクリア(キャンセル)して、新たなエラーなどを出力できる。
そんな処理方法まで、学習してしまった。
次は、
response.ContentType = " application/vnd.ms-excel"
これは、今から送るデータのタイプは、
" application/vnd.ms-excel"
ですよ、とブラウザに教えるために書きます。
response.ContentType = " imge/gif"
など、指定します。
文字データだけじゃなくて、ASPでいろいろと出来るんだね、、と感じた。
ここは、これで止めてしまったが、
自分の学習リストをメモ帳などのテキストで残しておき、
ヒマなとき、response.ContentType = " imge/gif" を調べる、、、
なんてやっておくと、幅広く知識を吸収できます。
response.AddHeader " content-disposition" , " inline; filename=dynamic.xls"
これは、詳しく載っていなかったけど、
動作や.AddHeaderから判断すると、ヘッダ情報にファイル名を載せている感じです。
response.write " <table width=200>"
response.write " <tr>"
↑この、Excelファイルなのに、普通のテーブルってのが不思議だけど、
※不思議に感じたら、調べろよ、なぜか?理由があるダロ。
疑問のまま素通りすると、私みたいな三流プログラマーなんですね。
こんな疑問も、テキストファイルのリストに書いておくといいですよ。
(貯まっていくと、イヤになったり、どれからやるか迷うので、
ほどほどにね。。。)
for i = 1 to 4
response.write " <td width=40>"
response.write i + i
response.write " </td>"
next
TDだから、横に数値を書き込んで、
※自分で知識があるから、さらっと読めるけど(読めたけど)
ASPやHTMLやったこと無い人は、<TD>って何?
から解析に入らないといけないので、
ソースを拾って読むには、ある程度の知識が必要とフト思いました。
response.write " <td width=40><b>=sum(A1:D1)</b></td>"
ここが一番感動した、
=Sum
とワークシート関数を入れている部分です。
普通にテーブルイメージなんですね。
※解析してて嬉しくなる、、そんな感覚があると思います。
下ばかり見て歩いてないで、周りをよく見て歩いていたら、
風がふいて・・・いいもの目撃・発見、、なんてことは無いかな(謎)
変な想像したアナタ、あたりだよたぶんその想像が(笑)
response.write " </tr>"
行の終了、
response.write " </table>"
テーブルの終了
response.flush
バッファを出力
response.end
ASP終了
って流れでした。
こんな感じで、拾ってきたソースサンプルを
自分の知識にすることができました。
なんて流れるように書いてるけど、
これは私の数少ない成功例
^^^^^^^^^^^^^^^^^^^^^^^^
実際は、解析途中で断念したり、
棚上げ後回しの拾ってきたソース君達も多いです。
全て、こんな方法で知識を吸収はできないのですが、
方法の1つとして、感覚だけでもつかんでもらえて、
成長のキッカケとなればうれしいです。
/*
* 4.終わりの挨拶(次回はアルのか?(爆))
*/
内容は同じだったのですが、
学習をテーマに加筆してみました。
たまにこんな感じで、加筆発行するかもしれませんが、
よろしくお願いします。
※あっ、うざいって人は、
http://www.mag2.com/m/0000099248.htm
でメルマガの方を解除して、
http://www.ken3.org/asp/
のHPをたまに覗きに来て下さい。
内容は同じなので。
何か読者の心に残れば、うれしいです。
*私の独り言をうまく消化してくださいね。
いつも失敗?のKen3でした。
~~~~~~~(↑オイオイ)
<SJIS--JISのコード変換>
こんにちは、三流プログラマーのKen3です。
今回は、
シフトJISからJISコードへ、コード変換を行ってみます。
拾い読みして、何かの参考となれば幸いです。
/*
* 1.今回のキッカケ
*/
VBA系のメルマガ( http://www.ken3.org/vba/ )
で、
シフトJISからJISコードへ、コード変換を行ってみたので、
ASP(VBScript)でもやってみます。
/*
* 2.VBAの自作関数を移植する。
*/
VBA系のメルマガ No.79 SJIS--JISコードの文字列を作成したい
で、下記の変換関数を作成しました。
※式、コードの意味などは、
http://www.ken3.org/backno/backno_vba16.html#79
を見てください。
'シフトJISコードの文字列を受け取り、JISコードを返す
Function SJIStoJIS(strSJISCODE As String) As String
Dim hi As Long
Dim lo As Long
'シフトJISコードの上位バイトを hi、下位バイトを lo とします。
hi = Val(" &h" & Mid(strSJISCODE, 1, 2))
lo = Val(" &h" & Mid(strSJISCODE, 3, 2))
'hi が 0x9f 以下の場合、 hi から 0x71 減じます。
'そうでない場合、 hi から 0xB1 減じます。
hi = hi - IIf(hi <= &H9F, &H71, &HB1)
'hi に 2 を乗じて、さらに 1 を加えます。
hi = hi * 2 + 1
'lo が 0x7F より大きい場合、 lo から 1 減じます。
If lo > &H7F Then lo = lo - 1
'lo が 0x9E 以上の場合、lo から 0x7D 減じて、hi に 1 加えます。
If lo >= &H9E Then
lo = lo - &H7D
hi = hi + 1
Else 'そうでない場合、 lo から 0x1F 減じます。
lo = lo - &H1F
End If
'結果を返します
SJIStoJIS = Right(" 0" & Hex(hi), 2) & Right(" 0" & Hex(lo), 2)
End Function
まぁ、VBScriptでも、普通に動くだろ、
変数やりターン値の AS XXXXX の型指定が出来ないから、それは取って
組み込み実行すると。
Microsoft VBScript 実行時エラー エラー '800a000d'
型が一致しません。: 'Val'
/cgi-bin/test/test061-1.asp, 行 61
オイオイ、Val関数って使えないのかよ。
※いつも思うけど、
型が一致しないとメッセージでるから、送り側の変数が悪いのか?
と見当違いのデバックしてたよ。
型が一致しません。じゃなくて、関数が見つかりませんのほうがいいのにね。
'シフトJISコードの上位バイトを hi、下位バイトを lo とします。
hi = Clng(" &h" & Mid(strSJISCODE, 1, 2))
lo = Clng(" &h" & Mid(strSJISCODE, 3, 2))
と
Clng関数を使用に変更しました。
えっ、まだダメなの?
Microsoft VBScript 実行時エラー エラー '800a000d'
型が一致しません。: 'IIf'
/cgi-bin/test/test061-1.asp, 行 66
あらら、IIfもVBScriptは無いんだぁ。
一行で書いてる処理をバラすか。
If hi <= &H9F Then
hi = hi - &H71 'hi が 0x9f 以下の場合、 hi から 0x71 減じます。
Else
hi = hi - &HB1 'そうでない場合、 hi から 0xB1 減じます。
End If
と
普通に書きました(笑)
/*
* 3.テストモジュールを組み込む
*/
http://www.ken3.org/cgi-bin/test/test061-1.asp?DATA=Ken3%82%CD%8EO%97%AC
でテストすると、
受け取ったデータは[Ken3は三流]です
バイト数は、10Byteです
1文字目は[K] をAscで変換すると75 さらにHexで16進数にすると4B
2文字目は[e] をAscで変換すると101 さらにHexで16進数にすると65
3文字目は[n] をAscで変換すると110 さらにHexで16進数にすると6E
4文字目は[3] をAscで変換すると51 さらにHexで16進数にすると33
5文字目は[は]をAscで変換すると-32051さらにHexで16進(SJIS)は82CD JISコードは244F
6文字目は[三]をAscで変換すると-29105さらにHexで16進(SJIS)は8E4F JISコードは3B30
7文字目は[流]をAscで変換すると-26708さらにHexで16進(SJIS)は97AC JISコードは4E2E
使用したテストモジュールは、
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<%@LANGUAGE=VBScript%>
<html>
<head>
<title>SJISからJISコードに変換、文字コード関係で遊ぶ</title>
</head>
<body>
<h2>SJISからJISコードに変換、文字コード関係で遊ぶ</h2>
<br>
自作したSJIS--JIS変換ルーチンを呼んでます。<br>
※詳細は、ソースと詳細解説のページを見てください。<br>
<hr>
<%
CHK_DATA = Request.QueryString(" DATA" ) 'パラメータの代入
'長さをチェックする
If Len(CHK_DATA) <> 0 Then '文字が入っていたら
Response.Write " 受け取ったデータは["
Response.Write Server.HTMLEncode(CHK_DATA) & " ]です<br>"
'関数を呼んで、バイト数を表示する
Response.Write " バイト数は、" & Byte_Count(CHK_DATA) & " Byteです<br>"
'文字数分ループして、コードを表示
For n = 1 To Len(CHK_DATA)
Response.Write n & " 文字目は"
strWORK = Mid(CHK_DATA, n, 1) 'n番目の文字を取り出す
Response.Write " [" & Server.HTMLEncode(strWORK) & " ] "
Response.Write " をAscで変換すると" & Asc(strWORK)
strCODE = Hex(Asc(strWORK))
If Len(strCODE) <= 2 Then '半角か?
Response.Write " さらにHexで16進数にすると" & strCODE
Else
Response.Write " さらにHexで16進(SJIS)は" & strCODE
Response.Write " JISコードは" & SJIStoJIS(strCODE)
End If
Response.Write " <BR>" & vbCRLF
Next
End If
%>
<HR>
<FORM ACTION=" test061-1.asp" METHOD=" GET" >
調査したい文字列を入力してください。<br>
<INPUT TYPE=" text" SIZE=" 30" NAME=" DATA" VALUE=" <%=CHK_DATA%> " >
<INPUT TYPE=" submit" VALUE=" コード調査開始" ><br>
↑いろいろと遊んでみてください↑
</FORM>
<br>
</body>
</html>
<%
'SJISコードの文字列を受け取り、JISコードの文字列を返す
Function SJIStoJIS(strSJISCODE)
Dim hi
Dim lo
'シフトJISコードの上位バイトを hi、下位バイトを lo とします。
hi = Clng(" &h" & Mid(strSJISCODE, 1, 2))
lo = Clng(" &h" & Mid(strSJISCODE, 3, 2))
If hi <= &H9F Then
hi = hi - &H71 'hi が 0x9f 以下の場合、 hi から 0x71 減じます。
Else
hi = hi - &HB1 'そうでない場合、 hi から 0xB1 減じます。
End If
'hi に 2 を乗じて、さらに 1 を加えます。
hi = hi * 2 + 1
'lo が 0x7F より大きい場合、 lo から 1 減じます。
If lo > &H7F Then lo = lo - 1
'lo が 0x9E 以上の場合、lo から 0x7D 減じて、hi に 1 加えます。
If lo >= &H9E Then
lo = lo - &H7D
hi = hi + 1
Else 'そうでない場合、 lo から 0x1F 減じます。
lo = lo - &H1F
End If
'結果を返します
SJIStoJIS = Right(" 0" & Hex(hi), 2) & Right(" 0" & Hex(lo), 2)
End Function
'文字列を受け取り、バイト数を返す
Function Byte_Count(strMOJI)
bcnt = 0
'文字数分ループして、コードを表示
For n = 1 To Len(strMOJI)
nCODE = Asc(Mid(strMOJI, n, 1)) 'n番目の文字コードを求める
If (nCODE And &HFF00) = 0 Then 'コードは1バイトか? *asp055
bcnt = bcnt + 1
Else
bcnt = bcnt + 2
End If
Next
'リターン値をセットする
Byte_Count = bcnt
End Function
%>
http://www.ken3.org/cgi-bin/test/test061-1.asp
でいろいろな文字を入れて、遊んでみてください。
/*
* 4.終わりの挨拶 </HTML>
*/
今回は、
・VBAで作成したJISコードの変換モジュールを移植してみました。
・Val関数は使えない
・IIf関数は使えない
って話でした
何かの参考となれば幸いです。
素朴な疑問やリクエスト、クレームなどがあったら、
掲示板 : http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi
に気軽に書き込んでください。
ASP、VBScript勉強中の三流プログラマーのKen3でした。
----------------------------------
関連項目(ただのバックナンバー紹介)
----------------------------------
VBA系のメルマガ
No.79 SJIS--JISコードの文字列を作成したい
http://www.ken3.org/backno/backno_vba16.html#79
変換の式、調査方法などを見てください。
<日付関係の復習、YYYYMMDDを返すFunction関数を作成する>
こんにちは、三流プログラマーのKen3です。
今回は、
日付、時刻関係の関数の復習
と
VBScriptにVBAでよく愛用していたFormat関数が使えないので、
自作でYYYYMMDDを返すFunction関数を作成してみます。
/*
* 1.今回のキッカケ
*/
HPで訪問者のログを収集してます。
http://www.ken3.org/cgi-bin/cnt/log100.asp
リンク元、GoogleやYahooからの探し物のお客さんが意外と多いです。
で、最近、よく見かけるのが、
http://www.google.co.jp/search?hl=ja&ie=UTF-8&q=ASP+Format&lr=lang_ja
と
ASP Formatとキーワードにして私のページにたどり着く人です。
ADO から MDB へのSQL文でFormat関数使用
http://www.ken3.org/cgi-bin/test/test040-1.asp
が、検索に引っかかってしまいます。
ADOのSQL文で使用可能な例題、
Select Format(WriteTime, 'YYYYMMDD') AS YYYYMMDD, Count(*) AS CNT
From log
GROUP BY Format(WriteTime, 'YYYYMMDD')
が拾われてしまうみたいです。
※Format関数、ASP(VBScript)には無いです、
そして、訪問者は、
ちぇ、期待してきたけど時間つぶしてしまった。。。
~~~~~~~~~~
と去って行くのであった。(マル)
少しでもお客さんを取り込むには、品揃えを充実させよう。
ってことで、復習を兼ねてYYYYMMDDを返す自作関数を作ってみます。
※Format関数って、12.5とか数値も扱ってたし、yyyy-mm-dd形式も?
って心の中で叫ばないでね・・・
/*
* 2.事前調査、各部分を取り出す関数を調べる
*/
ASP,VBScriptでFormat関数使えないんだよなぁ。。。
日付関係の関数を駆使して、文字列を作成するか。
えっと、現在時刻はNow関数でわかるから、
あとはこれを変換しながら、調べた関数をチェックしますか。
年 Year()
月 Month()
日 Day()
曜日 Weekday() 1:日曜〜7:土曜の数値を返す WeekDayName(数値)で曜日文字
時 Hour()
分 Minute()
秒 Second()
と、いろいろな変換関数存在するので、
関数に日付の値を渡すと変換できそうです。
http://www.ken3.org/cgi-bin/test/test062-1.asp
で、下記のテストプログラムを実行可能です。
<%@LANGUAGE=VBScript%>
<html>
<head>
<title>VBScript/Year/Month/Day/WeekDay/Hour/Minute/Secound 関数使用例</title>
</head>
<body>
<h2>VBScript関数<br>Year/Month/Day/WeekDay/Hour/Minute/Secound 関数使用例</h2>
<!-- Ken3 --><!-- #include file=" info.inc" -->
<br>
現在時刻を返すNow関数と組み合わせて下記の関数を使用してみました。<br>
<hr>
年 Year(変数や値)=<%=Year(Now)%> <br>
月 Month(変数や値)=<%=Month(Now)%> <br>
日 Day(変数や値)=<%=Day(Now)%> <br>
曜日 Weekday(変数や値)=<%=Weekday(Now)%> (←1:日曜〜7:土曜の数値)<br>
曜日の名前 WeekdayName(1〜7)=<%=WeekdayName(Weekday(Now))%> <br>
※通常日付を渡すんだけど、↑WeekdayNameだけ数値に対応した曜日文字を返す<br>
<hr>
時 Hour(変数や値)=<%=Hour(Now)%> <br>
分 Minute(変数や値)=<%=Minute(Now)%> <br>
秒 Second(変数や値)=<%=Second(Now)%> <br>
<hr>
<br>
</body>
</html>
/*
* 3.2003/6/5を20030605と一桁の月日は頭0を付ける
*/
あとは組み合わせて、一桁の時、頭0付けかぁ。
Right(" 0" & 変数, 2)
と小細工で、0と+してから、右端から2文字取るかな。
T = Now()
strMM = Right(" 0" & Month(T)), 2)
strDD = Right(" 0" & Day(T)), 2)
YYYYMMDD = Year(T) & strMM & strDD
うわ、なんかダサ(笑)
ここまで来たら、関数名もFormatYYMMDD(引数)でイイヤ
値を返すんだからFunctionの関数にしてと、
下記のようにしてみました。
http://www.ken3.org/cgi-bin/test/test062-1.asp
で、下記のテストプログラムを実行可能です。
<%@LANGUAGE=VBScript%>
<html>
<head>
<title>YYYYMMDDの文字列を返す関数を作ってみた</title>
</head>
<body>
<h2>YYYYMMDDの文字列を返す関数を作ってみた</h2>
<!-- Ken3 --><!-- #include file=" info.inc" -->
<br>
日付を渡すと、YYYYMMDDの形式で文字列を返す関数<br>
その名もFormatYYYYMMDD(笑)<br>
<hr>
FormatYYYYMMDD(Now)は<%=FormatYYYYMMDD(Now)%> と変換される。<br>
ログファイル名を作るときは、<br>
strLOGNAME = FormatYYYYMMDD(Now()) & " .log" なんて使う<br>
<%
strLOGNAME = FormatYYYYMMDD(Now()) & " .log"
%>
<%=strLOGNAME%> <br>
<hr>
なんかなぁ、、、もっと勉強して、使える関数作らないとなぁ。<br>
<hr>
<br>
<!-- Ken3 --><% Call OUT_SRC(" " ) 'ソースの表示関数を呼ぶ %>
<!-- Ken3 --><!-- #include file=" inc_mokuji.inc" -->
</body>
</html>
<!-- Ken3 --><!-- #include file=" out_src.inc" -->
<%
'受け取った日付データを変換してYYYYMMDDの文字列で返す
Function FormatYYYYMMDD(cnvMOTO)
'念のため日付型に変換可能かチェックする
If IsDate(cnvMOTO) = False Then
FormatYYYYMMDD = " " '変換エラーの時は空文字を返すようにする
Else
strMM = Right(" 0" & Month(cnvMOTO), 2) '月の変換
strDD = Right(" 0" & Day(cnvMOTO), 2) '日の変換
'リターン値で結果を返す
FormatYYYYMMDD = Year(cnvMOTO) & strMM & strDD
End If
End Function
%>
頻繁に、変換処理しないと、あまり関数化の意味無いかなぁ。
/*
* 4.終わりの挨拶 </HTML>
*/
ほんとは、偽のSQL文とか使って、
ADOでFormat関数を使えないかなぁと探ったけど、断念しました。
で、
なんか今回は、単なる日付関数紹介でした。
何かの参考となれば幸いです。
素朴な疑問やリクエスト、クレームなどがあったら、
掲示板 : http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi
に気軽に書き込んでください。
ASP、VBScript勉強中の三流プログラマーのKen3でした。
<Application.Lock .Unlockを使ってみた>
こんにちは、三流プログラマーのKen3です。
今回は、
同時アクセス、排他制御もどきで、
Application.Lock .Unlockを使ってみた
そんなお話です。
/*
* 1.今回のキッカケ
*/
HPで訪問者のログを収集してます。
DBに追加されていくので、削除しないとデータが増えてしまいます。
※当たり前でしょ(笑)
自社のサーバーなら、日替わり処理で、
タスクのスケジュールで、
SQL Delete文を発行すれば、済んでしまうんだけど、
レンタルサーバーだと、そんな処理タイミングを作ることが出来ません。
面倒だけど、削除のSQL文が入ったASPファイルを自分で実行してました。
なんとか、自動化できないかなぁ、、、と考えてて、
その日初めて起動した時に、8日前のデータを消すことにチャレンジしてみました。
※今のところ、うまくいってます。
/*
* 2.手で走らせてた削除のSQL文
*/
下記のような感じで、SQL文を作り、
strSQL = " Delete From log " '現在時刻、日付型は#で囲む
strSQL = strSQL & " Where WriteTime < #" & DateAdd(" d" , -7, Date) & " #"
削除のSQLを db.Execute(strSQL) で発行してました。
Sub DeleteMDB()
'ADO DB Connection オブジェクトを作成する、英文そのままじゃん
Set db=Server.CreateObject(" ADODB.Connection" )
'.Provider?プロバイダー?通信会社?じゃなくって
'データアクセスにはJet.OLEDB.4.0を使うことを設定
db.Provider = " Microsoft.Jet.OLEDB.4.0"
'次に、接続DBの位置を渡すので、Server.MapPathで変換して渡す
db.ConnectionString = Server.MapPath(" ../test/cnt.mdb" )
'やっとデータベースを開ける
db.open
'SQL文を作る
strSQL = " Delete From log " '現在時刻、日付型は#で囲む
strSQL = strSQL & " Where WriteTime < #" & DateAdd(" d" , -7, Date) & " #"
'SQL文を発行
db.Execute(strSQL)
'データベースも閉じようよ
db.Close
'お行儀よくオブジェクトも開放しましょう(通常は自動的に解放されるけど)
Set db = Nothing
End Sub
この削除の関数を、
その日、はじめて来た訪問者に実行させたくて、
共通のApplication変数に削除実施日を保存しておき、
現在時刻と削除実施日が違った場合のみ削除処理が走るように、
細工してみたいと思います。
/*
* 3.ロック処理で細工する
*/
作成した、削除のSQLを初回だけ呼ぶルーチンです。
<%
'日付の管理
Application.Lock 'ロックの設定
Application(" LOCK_FLG" ) = " ON"
'日替わりチェック
WTEMP = Application(" SDATE" )
DEL_FLG = " OFF"
If WTEMP <> Date Then
Application(" SDATE" ) = Date '日付の代入
DEL_FLG = " ON"
End If
Application.UnLock 'ロックの解除
'日替わり削除処理を呼ぶか判断
If DEL_FLG = " ON" Then
Call DeleteMDB()
End If
%>
同時にアクセスされて、変数を壊されるのがイヤだったので、
Application.Lock と Applicationオブジェクトへのアクセスをロックします。
Application(" LOCK_FLG" ) = " ON"
なんて意味深なことやっているけど、これは、気にしないでください。
※変数名に意味は無く、代入処理に意味があります。
フラグは使ってないんですね(笑)
AさんとBさんがほぼ同時にアクセスしてきました。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Aさん Bさん
Application.Lock 'ロックの設定 Application.Lock 'ロックの設定
Application(" LOCK_FLG" ) = " ON" Application(" LOCK_FLG" ) = " ON"
'日替わりチェック '日替わりチェック
WTEMP = Application(" SDATE" ) WTEMP = Application(" SDATE" )
DEL_FLG = " OFF" DEL_FLG = " OFF"
If WTEMP <> Date Then If WTEMP <> Date Then
Application(" SDATE" ) = Date Application(" SDATE" ) = Date
DEL_FLG = " ON" DEL_FLG = " ON"
End If End If
Application.UnLock 'ロックの解除 Application.UnLock 'ロックの解除
すると、Aさんのほうが少し早かったので、
先にApplication.Lockをかけました。
Bさんは、少し遅れてApplication.Lock の要求を出しました。
Aさんの
Application(" LOCK_FLG" ) = " ON"
は、普通にアプリケーション変数LOCK_FLGにONって文字列をセットします。
Bさんも、セットしようとアプリケーション変数LOCK_FLGにアクセスするも、
Aさんのかけた.Lockのおかげで、ここで解除となるまでまたされます。
Aさんの処理が進むと、
Application.UnLock 'ロックの解除
とロックが解除されます。
で、やっとBさんの処理、
Application(" LOCK_FLG" ) = " ON"
が開始されます。
こんな流れを作りたかったので、
Application.Lock
Application.UnLock
と
Application(" 変数名" ) = " 値"
で
小細工してみました。
/*
* 4.終わりの挨拶 </HTML>
*/
同時アクセス数が少なかったり、
止めて処理しているのが日付の比較だけなので(軽い処理なので)
ロックしている時間が短く、今のところ影響なく動作しています。
今回の処理は、別に2回、3回削除のSQL文走っても実害は無かったのですが、
ユニークな連番を振る処理などで、
排他的な処理をする時 And 軽めの処理限定で、
Application.Lock
Application.UnLock
を使うのも1つの手だなぁと思います。
何かの参考となれば幸いです。
素朴な疑問やリクエスト、クレームなどがあったら、
掲示板 : http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi
に気軽に書き込んでください。
ASP、VBScript勉強中の三流プログラマーのKen3でした。
<Session("変数名")で接続単位に変数を管理する>
こんにちは、三流プログラマーのKen3です。
今回は、
Session(" 変数名" )を使ってみた
そんなお話です。
/*
* 1.今回のキッカケ
*/
ASP間で値を保持、そんなことをやってみたくて、
アプリケーション全体(アクセスユーザー全体)で参照可能な変数の管理は、
No.42 Application(" XXXX" ) Application変数のテスト
http://www.ken3.org/backno/backno_asp09.html#42
で、軽く解説しました。
まぁ、アプリ全体(アクセスユーザー全体)でも、いいのですが、
アクセスしたユーザー単位で値を管理したい、
そんな時に使用するのが、
セッション変数 Session(" 項目名" )です。
/*
* 2.Session(" 変数名" )で簡単に使用可能
*/
Session(" 変数名" )で、ユーザー単位でセッション変数を設定可能です。
1つの接続で、1つのセッション変数が作成されます。
なんだかよくわからん?
えっと、ブラウザを立ち上げて1つのURLを表示したり、
接続をすると固有のセッションIDがふられ、
そのユーザー単位に、
Session(" A" ) = 10
Session(" B" ) = 20
と値の管理ができます。
あっそ?
冷たいなぁ、、、それを利用して、ユーザーの名前を一時的に覚えてみます。
※ブラウザ側でクッキー使用可能になっている必要があります。
ここも注意かなぁ。
/*
* 3.名前を一時的に覚えておく
*/
セッション単位の変数のテストとして、
ユーザー名を一時的に保持しておくサンプルを作ってみたいと思います。
簡単な流れは、
ユーザー名が送られてきたら(入力されたら)、
Session(" USERNAME" )に値を保持する
Session(" USERNAME" )が空なら、名前の入力フォームを表示
Request.QueryString(" DATA" ) にデータが入っていたら、
乱数を発生させ、勝敗の判定を行う。
そんな流れのプログラムを作ってみます。
http://www.ken3.org/cgi-bin/test/test064-1.asp
でテスト実行できます、遊んでみてください。
<%@LANGUAGE=VBScript%>
<html>
<head>
<title>セッション変数 Session(" USERNAME" ) で名前の管理</title>
</head>
<body>
<h2>セッション変数 Session(" USERNAME" ) で名前の管理</h2>
<h3>じゃんけんゲーム</h3><br>
<%
'ユーザー名が送られていたら、セッション変数にセットする
D = Request.QueryString(" UNAME" ) 'データを代入
If Len(D) <> 0 Then 'データあり
Session(" USERNAME" ) = D '名前の代入
End If
'パラメータをチェックする、セッション変数に名前が入っているか?
USER_NAME = Session(" USERNAME" )
'Lenで変数の長さをチェックする
If Len(Trim(USER_NAME)) = 0 Then '名前が未入力なら
Call INPUT_NAME() '名前入力フォームの表示
Else
D = Request.QueryString(" DATA" ) 'データを代入(選択された手)
If Len(D) = 1 Then 'データあり
Call HANTEI(D) '判断用の関数を呼ぶ
End If
Call INPUT_FORM() '入力用のフォームを表示する、再度入力させる
End If
%>
<hr>
アナタのIP Address=<%=Request.ServerVariables(" REMOTE_ADDR" )%> <br>
Session.SessionID=<%=Session.SessionID%> <br>
サーバー再起動時に同じセッションIDが振られることがあるが、<br>
通常は毎回違う値が表示される<br>
ブラウザを閉じてからまた開いたり<br>
隣のインターネット上同じIPの端末から2つ同時に開いたり
してテストしてみよう<br><hr>
</body>
</html>
<% '名前入力フォームの表示
Sub INPUT_NAME()
Response.Write " <HR>"
Response.Write " <FORM ACTION='test064-1.asp' METHOD='GET'>"
Response.Write " あなたのお名前は?<br>"
Response.Write " <INPUT TYPE='text' NAME='UNAME'><br>"
Response.Write " <INPUT TYPE='submit' VALUE='名前の登録'><br>"
Response.Write " </FORM>"
End Sub
%>
<% '入力フォームの表示(勝負する手を入力)
Sub INPUT_FORM()
Response.Write " <HR>"
Response.Write " <FORM ACTION='test064-1.asp' METHOD='GET'>"
Response.Write " <b>" & USER_NAME & " </b>さん、あなたの手は?<br>"
Response.Write " <INPUT TYPE='RADIO' NAME='DATA' VALUE='1'>1.グー<br>"
Response.Write " <INPUT TYPE='RADIO' NAME='DATA' VALUE='2'>2.チョキ<br>"
Response.Write " <INPUT TYPE='RADIO' NAME='DATA' VALUE='3'>3.パー<br>"
Response.Write " <INPUT TYPE='submit' VALUE='勝負する'><br>"
Response.Write " </FORM>"
End Sub
%>
<% '乱数を発生させて勝負する
Sub HANTEI(strNO) 'ユーザーの手を受取り判断する
Dim nCON 'コンピュータの手1〜3の数値が入る
Dim nPC 'ユーザーさんの手
Dim strTE(3) '(*1)配列変数を宣言
strTE(1) = " グー" '(*2)配列にメッセージを代入
strTE(2) = " チョキ"
strTE(3) = " パー"
'入力値の判断、エラーならメッセージを表示させ抜ける
'If文で1,2,3以外を判断する
If strNO <> " 1" And strNO <> " 2" And strNO <> " 3" Then
Response.Write " [" & strNO & " ]は不正な入力です"
Exit Sub '<--Exit Subを使用してここでプログラムを抜ける
End If
'コンピュータの手を決定
Randomize ' 乱数発生ルーチンを初期化します。
nCON = Int((3 * Rnd) + 1) '1 から 3 までの乱数を発生させます。
'結果判断と表示
'ユーザーの手を表示する
nPC = CInt(strNO) 'CInt関数で数値型に変換する
Response.Write USER_NAME & " さんの手は、"
Response.Write strTE(nPC) & " です<br>" '(*3)ここでnPC番目を表示
'(*4)同様にコンピュータの手を表示する
Response.Write " コンピュータの手は" & strTE(nCON) & " です<br>"
'結果の判断
'まず、引き分けを判断
If nPC = nCON Then Response.Write " 引き分けです<br>"
'次に自分が勝ちの手を判断 グーvsチョキ,チョキvsパー,パーvsグー
If nPC = 1 And nCON = 2 Then Response.Write " アナタの勝ちです<br>"
If nPC = 2 And nCON = 3 Then Response.Write " アナタの勝ちです<br>"
If nPC = 3 And nCON = 1 Then Response.Write " アナタの勝ちです<br>"
'コンピュータが勝ちか判断 グーvsパー,チョキvsグー,バーvsチョキ
If nPC = 1 And nCON = 3 Then Response.Write " 私(コンピュータ)の勝ちです<br>"
If nPC = 2 And nCON = 1 Then Response.Write " 私(コンピュータ)の勝ちです<br>"
If nPC = 3 And nCON = 2 Then Response.Write " 私(コンピュータ)の勝ちです<br>"
End Sub
%>
ポイントは、
~~~~~~~~~~~~
'ユーザー名が送られていたら、セッション変数にセットする
D = Request.QueryString(" UNAME" ) 'データを代入
If Len(D) <> 0 Then 'データあり
Session(" USERNAME" ) = D '名前の代入
End If
'パラメータをチェックする、セッション変数に名前が入っているか?
USER_NAME = Session(" USERNAME" )
'Lenで変数の長さをチェックする
If Len(Trim(USER_NAME)) = 0 Then '名前が未入力なら
と、
Session(" USERNAME" )を使用している場所です。
なんて書いたけど、
Session(" USERNAME" )で変数みたいに、
普通に出し入れできてるだけでした。
~~~~~~~~~~~~~~~~~~~~~~
アナタのIP Address=<%=Request.ServerVariables(" REMOTE_ADDR" )%> <br>
Session.SessionID=<%=Session.SessionID%> <br>
サーバー再起動時に同じセッションIDが振られることがあるが、<br>
通常は毎回違う値が表示される<br>
ブラウザを閉じてからまた開いたり<br>
隣のインターネット上同じIPの端末から2つ同時に開いたり
してテストしてみよう<br><hr>
なんて、書いてますが、
Session.SessionID が、
・起動毎に違うID、
・同じ会社の隣のマシーンからだと違う。
そんな感じのことを確認してみてください。
一時的に値を保持したり、
各接続単位(端末単位、ブラウザ)で、ASP間をまたいだ変数の管理が出来ます。
http://www.ken3.org/cgi-bin/test/test064-1.asp
でテスト実行できます、遊んでみてください。
/*
* 4.終わりの挨拶 </HTML>
*/
今回は、
簡単なSession変数のお話でした。
※活用例がショボかったけど、いろいろと使える手法です。
何かの参考となれば幸いです。
素朴な疑問やリクエスト、クレームなどがあったら、
掲示板 : http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi
に気軽に書き込んでください。
ASP、VBScript勉強中の三流プログラマーのKen3でした。
三流君のHP主な飛び先
分類別ガイド
[アクセスランキング ]
[サイトマップ ]
[リンク先・相互リンク先など ]
Ken3の日記(weblog) --
[広告・副収入系 ]
[プログラマー業務の愚痴 ]
[VBA系の話題 ]
[ASP系の話題 ]
[コンビニ系ネタ ]
[その他 ]
種類別のサービス紹介ページ
[イーバンク銀行(eBANK)の口座開設 ]
[ジャパンネットバンク(JNB)の口座開設 ]
[ネットで小遣い稼ぎ(笑) ]
[在宅プログラマー/SOHO ]
[プログラマー転職/派遣/就職 ]
[バナー広告アフィリエイトで稼ぐ実態 ]
種類別の商品 通信販売ページ
[自作PCパーツ ]
[ゲームソフトの通信販売 ]
[CD/DVD/ビデオ ]
[花・フラワー ]
[ダイエット・健康食品・サプリメントの通信販売 ]
[美容・化粧品の通信販売 ]
[ブランド・ジュエリー・香水の通信販売 ]
[グルメ・おいしい食品の通信販売 ]
[日本酒・焼酎の通信販売 ]
[ワインの通信販売 ]
[チーズの通信販売 ]
[デザート・お菓子の通信販売 ]
[ペット関係 ]
ネットワーク関係
ネットワーク技術が基礎から身につく 日経NETWORK
最適ソリューションを実現するための実務専門誌「日経システム構築」
Web制作・Webクリエイター - All About [Webプロデュース]
サンプル・ライブラリ・素材 - All About [JavaScript]
All About [ビジネスへのネット活用]
All About [ソフトウエアエンジニア]