c6fb2aaa3184abdb4025dcac73a2f6ec41c42b9a
Perl/Amazon/BrowseNodeSearch.md
... | ... | @@ -0,0 +1,157 @@ |
1 | +# XML::Simple を使って XML を読む |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- Amazon Web Services の BrowseNodeSearch の結果をXML::Simpleを使って解析し、子ノードを探索する。 |
|
6 | +- 親ノード/子ノードの表示だけ行いファイル保存はしないようにした。(2009/12/05) |
|
7 | +- AssociateTagを指定するようにした。(2011/10/27) |
|
8 | +- [Web版](http://www.takeash.net/cgi-bin/Amazon/BrowseNodes.cgi) |
|
9 | + |
|
10 | +## BrowseNodeSearch |
|
11 | +- 下記URLにリクエストすることで、あるBrowseNodeの子ノード一覧を取得できる。 |
|
12 | + - XXXXは調べたいBrowseNode。 |
|
13 | +``` |
|
14 | +http://webservices.amazon.co.jp/onca/xml |
|
15 | + ?Service=AWSECommerceService |
|
16 | + &Operation=BrowseNodeLookup |
|
17 | + &ResponseGroup=BrowseNodeInfo |
|
18 | + &AssociateTag=xxxx-22 |
|
19 | + &BrowseNodeId=XXXX |
|
20 | +``` |
|
21 | + |
|
22 | +## スクリプト |
|
23 | +- [BrowseNodes2.zip](BrowseNodes2.zip) |
|
24 | +```perl |
|
25 | +#!/usr/local/bin/perl |
|
26 | +# |
|
27 | +# BrowseNodes2.pl |
|
28 | +# Amazon Web Services BrowseNodes 探索スクリプト |
|
29 | +# by TakeAsh |
|
30 | +# |
|
31 | +# http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/BrowseNodeIDs.html |
|
32 | +# |
|
33 | +# 2009.12.05 v2.00 親ノード/子ノードの表示だけ行いファイル保存はしないようにした。 |
|
34 | +# 2011.10.27 v2.01 AssociateTagを指定するようにした。 |
|
35 | + |
|
36 | +use strict; |
|
37 | +use warnings; |
|
38 | +use utf8; |
|
39 | +use Encode; |
|
40 | +use URI::Amazon::APA; |
|
41 | +use LWP::UserAgent; |
|
42 | +use XML::Simple; |
|
43 | +use YAML::Syck; |
|
44 | + |
|
45 | +$YAML::Syck::ImplicitUnicode = 1; |
|
46 | + |
|
47 | +my $charsetConsole = 'CP932'; |
|
48 | +#my $charsetInFile = 'UTF-8'; |
|
49 | +#my $charsetOutFile = 'UTF-8'; |
|
50 | + |
|
51 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
52 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
53 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
54 | + |
|
55 | +my $confyaml = './ID.yaml'; |
|
56 | +my $conf = YAML::Syck::LoadFile( $confyaml ) |
|
57 | + or die( "$confyaml: $!\n" ); |
|
58 | + |
|
59 | +my $nodelistbaseyaml = './BrowseNodeIDs-JP.yaml'; |
|
60 | +my $nodelistbase = YAML::Syck::LoadFile( $nodelistbaseyaml ) |
|
61 | + or die( "$nodelistbaseyaml: $!\n" ); |
|
62 | + |
|
63 | +unless ( @ARGV ){ |
|
64 | + print "BrowseNodeId\tCategory\n"; |
|
65 | + foreach my $nodeid ( sort by_number ( keys( %{$nodelistbase} ) ) ){ |
|
66 | + print "$nodeid\t$nodelistbase->{$nodeid}\n"; |
|
67 | + } |
|
68 | + die( "usage: $0 <browse_node_id> [ <browse_node_id> ...]\n" ); |
|
69 | +} |
|
70 | +my $browsenodeid = join( ",", @ARGV ) || '465610'; |
|
71 | + |
|
72 | +my $u = URI::Amazon::APA->new( 'http://ecs.amazonaws.jp/onca/xml' ); |
|
73 | +$u->query_form( |
|
74 | + Service => 'AWSECommerceService', |
|
75 | + Operation => 'BrowseNodeLookup', |
|
76 | + ResponseGroup => 'BrowseNodeInfo', |
|
77 | + AssociateTag => $conf->{'ASSOCIATE_TAG'}, |
|
78 | + BrowseNodeId => $browsenodeid, |
|
79 | +); |
|
80 | +$u->sign( |
|
81 | + key => $conf->{'AWS_ACCESS_KEY_ID'}, |
|
82 | + secret => $conf->{'SECRET_ACCESS_KEY'}, |
|
83 | +); |
|
84 | + |
|
85 | +my $ua = LWP::UserAgent->new; |
|
86 | +my $r = $ua->get($u); |
|
87 | +if ( $r->is_success ){ |
|
88 | + my $content = XMLin( |
|
89 | + $r->content, |
|
90 | + ForceArray => [ 'BrowseNode', 'Error' ], |
|
91 | + KeyAttr => { 'BrowseNode' => '+BrowseNodeId' } |
|
92 | + ); |
|
93 | +# die( YAML::Syck::Dump( $content ) ); |
|
94 | + if ( my $errors = $content->{'BrowseNodes'}->{'Request'}->{'Errors'} ){ |
|
95 | + die( YAML::Syck::Dump( $errors ) ); |
|
96 | + } |
|
97 | + my $nodelist = $content->{'BrowseNodes'}->{'BrowseNode'}; |
|
98 | +# die( YAML::Syck::Dump( $nodelist ) ); |
|
99 | + foreach my $nodeid ( sort by_number ( keys( %{$nodelist} ) ) ){ |
|
100 | + my $node = $nodelist->{$nodeid}; |
|
101 | + print "Node\t\t$node->{'BrowseNodeId'}\t$node->{'Name'}\n"; |
|
102 | + printAncestors( $node ); |
|
103 | + my $children = $node->{'Children'}->{'BrowseNode'}; |
|
104 | + foreach my $childid ( sort by_number ( keys( %{$children} ) ) ){ |
|
105 | + my $child = $children->{$childid}; |
|
106 | + print "Child\t\t$child->{'BrowseNodeId'}\t$child->{'Name'}\n"; |
|
107 | + } |
|
108 | + } |
|
109 | +} else { |
|
110 | + die( $r->status_line, "\n" ); |
|
111 | +} |
|
112 | + |
|
113 | +exit; |
|
114 | + |
|
115 | +sub by_number |
|
116 | +{ |
|
117 | + $a <=> $b; |
|
118 | +} |
|
119 | + |
|
120 | +sub printAncestors |
|
121 | +{ |
|
122 | + my( $browsenode ) = @_; |
|
123 | + if ( my $ancestors = $browsenode->{'Ancestors'}->{'BrowseNode'} ){ |
|
124 | + foreach my $nodeid ( keys( %{$ancestors} ) ){ |
|
125 | + my $node = $ancestors->{$nodeid}; |
|
126 | + print "Ancestor\t$node->{'BrowseNodeId'}\t$node->{'Name'}\n"; |
|
127 | + printAncestors( $node ); |
|
128 | + } |
|
129 | + } |
|
130 | +} |
|
131 | + |
|
132 | +# EOF |
|
133 | +``` |
|
134 | + |
|
135 | +## エラーメッセージ対応 |
|
136 | +- XML::Simple で下記エラーメッセージが表示される。 |
|
137 | +``` |
|
138 | +could not find ParserDetails.ini in D:/Perl64/site/lib/XML/SAX |
|
139 | +``` |
|
140 | +- 次の行を追加する。 |
|
141 | +``` |
|
142 | +$XML::Simple::PREFERRED_PARSER = 'XML::Parser'; |
|
143 | +``` |
|
144 | + |
|
145 | +- [xml - Could not find ParserDetails.ini - Stack Overflow](https://stackoverflow.com/questions/%32%32%30%32%33%38%39%34) |
|
146 | + |
|
147 | +## リンク |
|
148 | +- [[Perl/XML-XPath]] |
|
149 | + |
|
150 | +- [CPAN:XML-Simple](http://search.cpan.org/dist/XML-Simple) |
|
151 | +- [CPAN:URI-Amazon-APA](http://search.cpan.org/dist/URI-Amazon-APA) |
|
152 | + |
|
153 | +- [Perl 開発者のための XML: 第 1 回 XML と Perl -- 魔法の組み合わせ](http://www.ibm.com/developerworks/jp/xml/library/x-xmlperl1.html) |
|
154 | +- [作って学ぶ、今どきのWebサービス: 第3回 XML::SimpleであらゆるXML文書を料理する](http://www.itmedia.co.jp/enterprise/articles/0702/26/news011.html) |
|
155 | +- [XML::Simple は遅い説における意外な落とし穴](http://iandeth.dyndns.org/mt/ian/archives/000589.html) |
|
156 | + |
|
157 | +- [PerlでAmazon Product Advertising APIのBrowseNodeLookupを行なう](http://tech.lampetty.net/tech/index.php/archives/338) |
|
... | ... | \ No newline at end of file |
Perl/Amazon/Home.md
... | ... | @@ -0,0 +1,21 @@ |
1 | +# Amazon Web Services |
|
2 | +[[_TOC_]] |
|
3 | +~~#ls2~~ |
|
4 | + |
|
5 | +## リンク |
|
6 | +- Amazon Web Services [日本語](http://aws.amazon.com/jp/) / [英語](http://aws.amazon.com/) |
|
7 | + - [Product Advertising API](https://affiliate.amazon.co.jp/gp/advertising/api/detail/main.html) |
|
8 | + - [Release Notes](http://aws.amazon.com/releasenotes/Product-Advertising-API) |
|
9 | + - [Product Advertising API Developer Guide](http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/) |
|
10 | + - [Anatomy of a REST Request (Locale Endpoint)](http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/AnatomyOfaRESTRequest.html) |
|
11 | + - [Browse Node IDs](http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/BrowseNodeIDs.html) |
|
12 | +<!----- [[Amazon E-Commerce Service API (2005-10-05):http://docs.amazonwebservices.com/AWSEcommerceService/2005-10-05/]]--> |
|
13 | +<!------ [[Browse Nodes for JP:http://docs.amazonwebservices.com/AWSEcommerceService/2005-10-05/ApiReference/JPBrowseNodesArticle.html]]--> |
|
14 | + - [ファイル名について](http://www.amazon.co.jp/gp/help/customer/display.html?ie=UTF8&nodeId=200129350) |
|
15 | + - [Amazon Web Services ブログ](http://aws.typepad.com/aws_japan/) |
|
16 | + - [Amazon アソシエイト (アフィリエイト)](https://affiliate.amazon.co.jp/) |
|
17 | +- [perl - URI::Amazon::APA released!](http://blog.livedoor.jp/dankogai/archives/51211577.html) |
|
18 | + - [CPAN:URI-Amazon-APA](http://search.cpan.org/dist/URI-Amazon-APA) |
|
19 | +- [Amazon Web サービス(AWS)の概要](http://www.rfs.jp/sb/perl/10/aws01.html) |
|
20 | +- [Shizラボ](http://shizlabs.amonya.com/) / [技術資料](http://shizlabs.amonya.com/tecnorogy/) / [Amazon商品画像のカスタマイズ(理論編)](http://shizlabs.amonya.com/amazon/image-uri01.html) |
|
21 | +- [PE2プレイ記録ほか](http://parasiteeve2.blog65.fc2.com/) / [Amazonの画像加工について(まとめ)](http://parasiteeve2.blog65.fc2.com/blog-entry-33.html) |
|
... | ... | \ No newline at end of file |
Perl/Amazon/getImages.md
... | ... | @@ -0,0 +1,346 @@ |
1 | +# 大きな画像を表示する |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- ASINから大きな画像のURIを求めて存在するかどうか確認する。 |
|
6 | +- 「content-type」が「image/jpeg」なら存在する、「image/gif」なら存在しない。 |
|
7 | + |
|
8 | +## 動作サンプル |
|
9 | +- [CGI Top](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi) |
|
10 | + - &amazon(B001EQ6A80);<br /> |
|
11 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B001EQ6A80) |
|
12 | + - &amazon(B002MZZ33K);<br /> |
|
13 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002MZZ33K) |
|
14 | + - &amazon(B0026RIRRS);<br /> |
|
15 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B0026RIRRS) |
|
16 | + - &amazon(B002H9WBNQ);<br /> |
|
17 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002H9WBNQ) |
|
18 | + - &amazon(B002L16FZU);<br /> |
|
19 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002L16FZU) |
|
20 | + - &amazon(B0019JNTQS);<br /> |
|
21 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B0019JNTQS) |
|
22 | + - &amazon(B002SW3N16);<br /> |
|
23 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002SW3N16) |
|
24 | + - &amazon(4775307614);<br /> |
|
25 | +[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=4775307614&SHOT=IN) |
|
26 | + |
|
27 | +## Bookmarklet |
|
28 | +``` |
|
29 | +javascript:location='http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN='+(location.href.match(/\/(dp|ASIN|product)\/([\w]+)/))[2]; |
|
30 | +``` |
|
31 | + |
|
32 | +## スクリプト |
|
33 | +- [getImages.zip](getImages.zip) |
|
34 | +```perl |
|
35 | +#!/usr/bin/perl |
|
36 | + |
|
37 | +use strict; |
|
38 | +use warnings; |
|
39 | +use utf8; |
|
40 | +use Encode; |
|
41 | +use LWP::UserAgent; |
|
42 | +use URI::Amazon::APA; |
|
43 | +use XML::Simple; |
|
44 | +use YAML::Syck; |
|
45 | +use CGI::Pretty qw( -no_xhtml *table *ol ); # //HTML 4.01 Transitional//EN |
|
46 | +use URI::Escape; |
|
47 | + |
|
48 | +$YAML::Syck::ImplicitUnicode = 1; |
|
49 | +$CGI::POST_MAX = 1024; |
|
50 | + |
|
51 | +binmode( STDIN, ":utf8" ); |
|
52 | +binmode( STDOUT, ":utf8" ); |
|
53 | +binmode( STDERR, ":utf8" ); |
|
54 | + |
|
55 | +# 自動フラッシュ有効化 (バッファリングを無効化) |
|
56 | +$| = 1; |
|
57 | + |
|
58 | +my $confyaml = './ID.yaml'; |
|
59 | +my $conf = YAML::Syck::LoadFile( $confyaml ) or die( "$confyaml: $!\n" ); |
|
60 | + |
|
61 | +my $cginame = 'Amazon getImages-JP'; |
|
62 | +my $ImageUriBase = |
|
63 | + 'http://images-jp.amazon.com/images/P/%ASIN%.09.%SHOT%._SC%SIZE%ZZZZZZ_.jpg'; |
|
64 | +my $NoImageUri = 'http://images-jp.amazon.com/images/G/09/nav2/dp/no-image-no-ciu.gif'; |
|
65 | +my $DetailUri = 'http://www.amazon.co.jp/dp/%ASIN%/'; |
|
66 | +my $CustomerImageUri = 'http://www.amazon.co.jp/gp/customer-media/product-gallery/%ASIN%'; |
|
67 | + |
|
68 | +my @ShotsFixList = ( |
|
69 | + { 'name' => 'Main', 'key' => 'MAIN', }, |
|
70 | + { 'name' => 'Top', 'key' => 'TOPP', }, |
|
71 | + { 'name' => 'Bottom', 'key' => 'BOTT', }, |
|
72 | + { 'name' => 'Left', 'key' => 'LEFT', }, |
|
73 | + { 'name' => 'Right', 'key' => 'RGHT', }, |
|
74 | + { 'name' => 'Front', 'key' => 'FRNT', }, |
|
75 | + { 'name' => 'Back', 'key' => 'BACK', }, |
|
76 | +); |
|
77 | + |
|
78 | +my @ShotsVarList = qw( PT IN ); |
|
79 | +my %ShotsTypeList = ( |
|
80 | + 0 => 'PIECE SHOTS / 書籍以外のその他の画像', |
|
81 | + 1 => 'INTERIOR SHOTS / 書籍のその他の画像', |
|
82 | +); |
|
83 | + |
|
84 | +my @SizeList = ( |
|
85 | + { 'name' => 'Large', 'key' => 'RM' }, |
|
86 | + { 'name' => 'Medium', 'key' => 'L' }, |
|
87 | +# { 'name' => 'Small', 'key' => 'M' }, |
|
88 | +); |
|
89 | + |
|
90 | +my $Step = 20; |
|
91 | +my %PageLabels = (); |
|
92 | +for( my $i=0; $i * $Step < 99; ++$i){ |
|
93 | + $PageLabels{ $i } = 'PT' . substr( '0' . ( $i * $Step + 1 ), -2 ) |
|
94 | + . '-PT'. substr( '0' . ( ( $i + 1 ) * $Step ), -2 ) |
|
95 | +} |
|
96 | +$PageLabels{ 0 } = 'Main, ' . $PageLabels{ 0 }; |
|
97 | +my $PageMax = @{ [ sort { $b <=> $a } ( keys( %PageLabels ) ) ] }[ 0 ]; |
|
98 | +$PageLabels{ $PageMax } =~ s/\d+$/99/; |
|
99 | + |
|
100 | +my $q = new CGI; |
|
101 | +$q->charset('utf-8'); |
|
102 | +my $cgipath = $q->url( -absolute => 1 ); |
|
103 | + |
|
104 | +my $URI = $q->param( 'URI' ) || ''; |
|
105 | +my $ASIN = ''; |
|
106 | +unless ( $ASIN = $q->param( 'ASIN' ) ){ |
|
107 | + # Perl 5.10 |
|
108 | + $URI =~ /\/(dp|ASIN|product)\/(?'asin'[\w]+)/; |
|
109 | + $ASIN = $+{asin}; |
|
110 | + # Perl 5.8 |
|
111 | + #$URI =~ /\/(dp|ASIN|product)\/([\w]+)/; |
|
112 | + #$ASIN = $2; |
|
113 | +} |
|
114 | +if ( $ASIN ){ |
|
115 | + $URI = $DetailUri; |
|
116 | + $URI =~ s/%ASIN%/$ASIN/; |
|
117 | +} |
|
118 | +my $SHOT = ( $q->param( 'SHOT' ) ) ? 1 : 0; |
|
119 | +my $shottype = $ShotsVarList[ $SHOT ]; |
|
120 | + |
|
121 | +my $PAGE = $q->param( 'PAGE' ) || 0; |
|
122 | +if ( $PAGE < 0 || $PageMax < $PAGE ){ |
|
123 | + $PAGE = 0; |
|
124 | +} |
|
125 | + |
|
126 | +my $MOD = $q->param( 'MOD' ) || 0; |
|
127 | + |
|
128 | +my $ua = LWP::UserAgent->new( keep_alive => ( 7 + $Step ) * 3 ); |
|
129 | + |
|
130 | +my @Anchors = (); |
|
131 | + |
|
132 | +printHeader(); |
|
133 | + |
|
134 | +if ( !$ASIN || $MOD ){ |
|
135 | + print $q->start_form( -action => $q->url ), |
|
136 | + $q->table( { -summary => 'enter ASIN and so on.', -border => 1 }, |
|
137 | + $q->Tr( |
|
138 | + $q->th( 'ASIN' ), |
|
139 | + $q->td( $q->textfield( -name => 'ASIN', -value => $ASIN ) ) |
|
140 | + ), |
|
141 | + $q->Tr( |
|
142 | + $q->th( 'URI' ), |
|
143 | + $q->td( $q->textfield( -name => 'URI', -value => $URI, -size => 80 ) ) |
|
144 | + ), |
|
145 | + $q->Tr( $q->th( 'SHOT' ), $q->td( $q->popup_menu( |
|
146 | + -name => 'SHOT', |
|
147 | + -values => [sort {$a<=>$b} keys(%ShotsTypeList)], |
|
148 | + -default => $SHOT, |
|
149 | + -labels => \%ShotsTypeList, |
|
150 | + ) ) ), |
|
151 | + $q->Tr( $q->th( 'PAGE' ), $q->td( $q->popup_menu( |
|
152 | + -name => 'PAGE', |
|
153 | + -values => [sort {$a<=>$b} keys(%PageLabels)], |
|
154 | + -default => $PAGE, |
|
155 | + -labels => \%PageLabels, |
|
156 | + ) ) ), |
|
157 | + $q->Tr( $q->td( |
|
158 | + { -colspan => 2, -align => 'center' }, |
|
159 | + $q->submit, " ", $q->reset |
|
160 | + ) ), |
|
161 | + ), |
|
162 | + $q->end_form; |
|
163 | +} else { |
|
164 | + my $u = URI::Amazon::APA->new( 'http://ecs.amazonaws.jp/onca/xml' ); |
|
165 | + $u->query_form( |
|
166 | + Service => 'AWSECommerceService', |
|
167 | + Operation => 'ItemLookup', |
|
168 | + ResponseGroup => 'ItemAttributes,Images', |
|
169 | + AssociateTag => $conf->{'ASSOCIATE_TAG'}, |
|
170 | + ItemId => $ASIN, |
|
171 | + ); |
|
172 | + $u->sign( |
|
173 | + key => $conf->{'AWS_ACCESS_KEY_ID'}, |
|
174 | + secret => $conf->{'SECRET_ACCESS_KEY'}, |
|
175 | + ); |
|
176 | + |
|
177 | + my $r = $ua->get($u); |
|
178 | + if ( $r->is_success ){ |
|
179 | + print $q->h2( 'Bibliography' ); |
|
180 | + my $content = XMLin( |
|
181 | + $r->content, |
|
182 | + ForceArray => [ |
|
183 | + 'Item', 'Error', 'DetailPageURL', 'SalesRank', 'ProductGroup', 'Title', |
|
184 | + ], |
|
185 | + KeyAttr => { 'Item' => '+ASIN', }, |
|
186 | + ); |
|
187 | + my( $title, $detailpageurl, $customerimage ); |
|
188 | + if ( my $errors = $content->{'Items'}->{'Request'}->{'Errors'}->{'Error'} ){ |
|
189 | + printErrors( $errors ); |
|
190 | + } else { |
|
191 | + my $items = $content->{'Items'}->{'Item'}; |
|
192 | + my $item = $items->{$ASIN}; |
|
193 | + $title = $item->{'ItemAttributes'}->{'Title'}; |
|
194 | + $detailpageurl = $item->{'DetailPageURL'}[0]; |
|
195 | + $detailpageurl = decode( 'utf8', uri_unescape( $detailpageurl ) ); |
|
196 | + # $detailpageurl =~ s#/[^/]+/(?=dp/)#/#; |
|
197 | + # $detailpageurl = uri_unescape( $detailpageurl ); |
|
198 | + $customerimage = $CustomerImageUri; |
|
199 | + $customerimage =~ s/%ASIN%/$ASIN/; |
|
200 | + } |
|
201 | + |
|
202 | + my $pagelabel = $PageLabels{ $PAGE }; |
|
203 | + $pagelabel =~ s/PT/$ShotsVarList[ $SHOT ]/g; |
|
204 | + print $q->table( { -summary => 'Bibliography', -border => 1 }, |
|
205 | + ( $title ) ? $q->Tr( |
|
206 | + $q->th( 'TITLE' ) , |
|
207 | + $q->td( |
|
208 | + $q->a( |
|
209 | + { -href => $detailpageurl || $URI . $conf->{'ASSOCIATE_TAG'} }, |
|
210 | + $title |
|
211 | + ), $q->br(), |
|
212 | + $q->a( { -href => $customerimage }, 'Customer Image' ) |
|
213 | + ) |
|
214 | + ) : '', |
|
215 | + $q->Tr( $q->th( 'ASIN' ), $q->td( $ASIN ) ), |
|
216 | + $q->Tr( $q->th( 'SHOT' ), $q->td( $ShotsTypeList{ $SHOT } ) ), |
|
217 | + $q->Tr( $q->th( 'PAGE' ), $q->td( $pagelabel ) ), |
|
218 | + ); |
|
219 | + |
|
220 | + print $q->h2( 'Search Results' ); |
|
221 | + $ImageUriBase =~ s/%ASIN%/$ASIN/; |
|
222 | + print $q->p( { -id => 'status' }, 'Now searching...' ); |
|
223 | + if ( $PAGE == 0 ){ |
|
224 | + foreach my $shot ( @ShotsFixList ){ |
|
225 | + my $ImageUri = $ImageUriBase; |
|
226 | + my $shotkey = $shot->{'key'}; |
|
227 | + $ImageUri =~ s/%SHOT%/$shotkey/; |
|
228 | + searchSize( $ImageUri, $shot->{'name'} ); |
|
229 | + } |
|
230 | + } |
|
231 | + for( my $i=$PAGE*$Step; $i<($PAGE+1)*$Step && $i<99; ++$i ){ |
|
232 | + my $ImageUri = $ImageUriBase; |
|
233 | + my $shotkey = $shottype . substr( '0' . ( $i + 1 ), -2 ); |
|
234 | + $ImageUri =~ s/%SHOT%/$shotkey/; |
|
235 | + searchSize( $ImageUri, $shotkey ); |
|
236 | + } |
|
237 | + if ( @Anchors ){ |
|
238 | + print $q->h2( $q->a( { -name => 'INDEX', -id => 'INDEX' }, 'Index' ) ), |
|
239 | + $q->start_ol(), |
|
240 | + $q->li( [ map { $q->a( { -href => '#' . $_ }, $_ ) } @Anchors ] ), |
|
241 | + $q->end_ol(); |
|
242 | + } else { |
|
243 | + print $q->p( $q->img( |
|
244 | + { -src => $NoImageUri, -title => 'No Image', -alt => 'No Image' } |
|
245 | + ) ); |
|
246 | + } |
|
247 | + print $q->p( $q->a( { -href => '#top', -name => 'bottom' }, 'Page Top' ) ); |
|
248 | + } else { |
|
249 | + print $q->p( $r->status_line ); |
|
250 | + } |
|
251 | +} |
|
252 | + |
|
253 | +printFooter(); |
|
254 | + |
|
255 | +exit; |
|
256 | + |
|
257 | +sub printHeader |
|
258 | +{ |
|
259 | + my $jscript = qq{ |
|
260 | + function changeStatus(){ |
|
261 | + document.getElementById('status').innerHTML = 'Finished.' |
|
262 | + + ( ( document.getElementById( 'INDEX' ) ) |
|
263 | + ? '<br><a href=\"#INDEX\">Index<'+'/a>' |
|
264 | + : '' ); |
|
265 | + } |
|
266 | + }; |
|
267 | + print $q->header(), |
|
268 | + $q->start_html( |
|
269 | + -title => $cginame, |
|
270 | + -lang => 'ja-JP', |
|
271 | + -head => [ |
|
272 | + $q->meta( { -http_equiv=>'Content-style-type', -content=>"text/css" } ), |
|
273 | + $q->meta( { -http_equiv=>'Content-script-type', -content=>"text/javascript" } ), |
|
274 | + ], |
|
275 | + -style => { 'src'=>'/take.css' }, |
|
276 | + -script => $jscript, |
|
277 | + -onLoad => 'changeStatus()', |
|
278 | + ), |
|
279 | + $q->h1( $q->a( { -name => 'top' }, $cginame ) ), |
|
280 | + $q->ul( |
|
281 | + $q->li( $q->a( { -href => $cgipath }, 'CGI Top' ) ), |
|
282 | + ( $ASIN && !$MOD ) |
|
283 | + ? $q->li( [ $q->a( { |
|
284 | + -href => "$cgipath?ASIN=$ASIN&SHOT=$SHOT&PAGE=$PAGE&MOD=1&URI=" |
|
285 | + . uri_escape_utf8( $URI ) |
|
286 | + }, 'Modify' ), ] ) |
|
287 | + : '', |
|
288 | + ); |
|
289 | +} |
|
290 | + |
|
291 | +sub printFooter |
|
292 | +{ |
|
293 | + print $q->end_html . "\n"; |
|
294 | +} |
|
295 | + |
|
296 | +sub printErrors |
|
297 | +{ |
|
298 | + my( $errors ) = @_; |
|
299 | +# print $q->h2( 'Error' ); |
|
300 | + print $q->start_table( { -summary => 'Error Message', -border => 1 } ); |
|
301 | + foreach my $error ( @{$errors} ){ |
|
302 | + print $q->Tr( $q->th( $error->{'Code'} ), $q->td( $error->{'Message'} ) ); |
|
303 | + } |
|
304 | + print $q->end_table(); |
|
305 | +} |
|
306 | + |
|
307 | +sub searchSize |
|
308 | +{ |
|
309 | + my( $ImageUriBase, $Shot ) = @_; |
|
310 | + foreach my $size ( @SizeList ){ |
|
311 | + my $ImageUri = $ImageUriBase; |
|
312 | + my $sizekey = $size->{'key'}; |
|
313 | + $ImageUri =~ s/%SIZE%/$sizekey/; |
|
314 | + my $title = $Shot . '_' . $size->{'name'}; |
|
315 | + #print $title . ': '; |
|
316 | + my $r = $ua->request( HTTP::Request->new( HEAD => $ImageUri ) ); |
|
317 | + if ( $r->header( 'content-type' ) eq 'image/jpeg' ){ |
|
318 | + #print 'Exist.' . $q->br(); |
|
319 | + print $q->p( |
|
320 | + $title, $q->a( { -name => $title, -href => '#INDEX' }, '*' ), $q->br(), |
|
321 | + $q->img( { -src => $ImageUri, -title => $title, -alt => $title, } ) |
|
322 | + ); |
|
323 | + push( @Anchors, $title ); |
|
324 | + last; |
|
325 | + } else { |
|
326 | + #print 'Not exist.' . $q->br(); |
|
327 | + } |
|
328 | + } |
|
329 | +} |
|
330 | + |
|
331 | +# EOF |
|
332 | +``` |
|
333 | + |
|
334 | +## リンク |
|
335 | +- [Shizラボ](http://shizlabs.amonya.com/) / [技術資料](http://shizlabs.amonya.com/tecnorogy/) / [Amazon商品画像のカスタマイズ(理論編)](http://shizlabs.amonya.com/amazon/image-uri01.html) |
|
336 | + |
|
337 | +- [PE2プレイ記録ほか](http://parasiteeve2.blog65.fc2.com/) |
|
338 | + - [Amazonの画像加工について(まとめ)](http://parasiteeve2.blog65.fc2.com/blog-entry-33.html) |
|
339 | + - [Amazonの画像加工(ツール編5)ASINから利用可能な全画像を求める・5](http://parasiteeve2.blog65.fc2.com/blog-entry-372.html) |
|
340 | + - [Amazonの画像加工(ツール編7)ASINから利用可能な全画像を求める・6](http://parasiteeve2.blog65.fc2.com/blog-entry-425.html) |
|
341 | + |
|
342 | +- [rubyu備忘録](http://d.hatena.ne.jp/ruby-U/) / [perlとpython用encodeURIComponent()](http://d.hatena.ne.jp/ruby-U/20081110/1226313786) |
|
343 | + |
|
344 | +- [CPAN:URI-Amazon-APA](http://search.cpan.org/dist/URI-Amazon-APA) |
|
345 | +- [CPAN:CGI](http://search.cpan.org/dist/CGI) |
|
346 | +- [CPAN:URI](http://search.cpan.org/dist/URI) / [CPAN:URI/URI/Escape.pm](http://search.cpan.org/dist/URI/URI/Escape.pm) |
|
... | ... | \ No newline at end of file |
Perl/ApacheErrorLogFormatter.md
... | ... | @@ -0,0 +1,202 @@ |
1 | +[[_TOC_]] |
|
2 | +---- |
|
3 | +# 概要 |
|
4 | +- Apache の error_log を HTML テーブルとして整形する。 |
|
5 | +- mod_security 対応。 |
|
6 | + |
|
7 | +# 動作サンプル |
|
8 | +- http://www.takeash.net/AELF/ |
|
9 | + |
|
10 | +# ソース |
|
11 | +- [AELF.zip](AELF.zip) |
|
12 | + |
|
13 | +## index.cgi |
|
14 | +```perl |
|
15 | +#!/usr/bin/perl |
|
16 | +# Apache のエラーログを整形 |
|
17 | + |
|
18 | +use strict; |
|
19 | +use warnings; |
|
20 | +use utf8; |
|
21 | +use Encode; |
|
22 | +use CGI::Pretty qw( -no_xhtml *table *ol ); |
|
23 | +use Net::DNS::Resolver; |
|
24 | + |
|
25 | +$CGI::POST_MAX = 80 * 1024; |
|
26 | + |
|
27 | +my $charsetConsole = 'UTF-8'; |
|
28 | +#my $charsetConsole = 'CP932'; |
|
29 | +my $charsetFile = 'UTF-8'; |
|
30 | + |
|
31 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
32 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
33 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
34 | + |
|
35 | +my $cgiName = 'Apache Error Log Formatter'; |
|
36 | + |
|
37 | +my @pair_type = ( |
|
38 | + { # mod_security |
|
39 | + header => qr/(ModSecurity:.*\.)\s(\[.*)\s*/, |
|
40 | + to_pair => qr/\[\S+\s[^\]]+\]\s*/, |
|
41 | + to_keyval => qr/\[(\S+)\s"([^\]]+)"\]\s*/, |
|
42 | + }, |
|
43 | + { # default, detail部無し |
|
44 | + header => qr/(.*)\s*/, |
|
45 | + }, |
|
46 | +); |
|
47 | + |
|
48 | +my $q = new CGI; |
|
49 | +$q->charset( $charsetFile ); |
|
50 | +my $br = $q->br(); |
|
51 | + |
|
52 | +my %processer = ( |
|
53 | + Client => \&toHostName, |
|
54 | + data => sub{ |
|
55 | + my $word = shift; |
|
56 | + $word =~ s/(\s(ARGS|ARGS_NAMES):)/$1$br/; |
|
57 | + return $word; |
|
58 | + }, |
|
59 | +); |
|
60 | + |
|
61 | +my $log = $q->param('LOG') || ''; |
|
62 | +if ( ( ! $ENV{'SERVER_ADDR'} ) && ( ! $log ) && ( my $file = $q->param('FILE') ) ){ |
|
63 | + open( my $IN, "<:encoding($charsetFile)", $file ) or die( "$file: $!\n" ); |
|
64 | + my @body = <$IN>; |
|
65 | + close( $IN ); |
|
66 | + $log = join( "", @body ); |
|
67 | +} |
|
68 | + |
|
69 | +print $q->header( |
|
70 | + -type => 'text/html', |
|
71 | + -charset => $charsetConsole, |
|
72 | +); |
|
73 | +print $q->start_html( |
|
74 | + -title => $cgiName, |
|
75 | + -head => [ |
|
76 | + $q->meta( { -http_equiv=>'Content-Type', -content=>"text/html; charset=" . $charsetConsole } ), |
|
77 | + $q->meta( { -http_equiv=>'Content-style-type', -content=>"text/css" } ), |
|
78 | + ], |
|
79 | + -style => [ { 'src'=>'/take.css' }, ], |
|
80 | +); |
|
81 | +print $q->h1( $cgiName ); |
|
82 | + |
|
83 | +if ( $log ){ |
|
84 | + print_result( $log ); |
|
85 | +} else { |
|
86 | + print_form(); |
|
87 | +} |
|
88 | + |
|
89 | +print $q->end_html . "\n"; |
|
90 | + |
|
91 | +exit; |
|
92 | + |
|
93 | +sub print_result |
|
94 | +{ |
|
95 | + my( $log ) = @_; |
|
96 | + $log =~ s/\r\n|\n\r/\n/gmx; |
|
97 | + $log =~ s/\r/\n/gmx; |
|
98 | + $log =~ s/"([^\"]*)"/'"'.encodeURIComponent($1).'"'/gmxe; |
|
99 | + |
|
100 | + print $q->p( $q->a( { -href => $q->url( -absolute => 1 ) }, 'form' ) ); |
|
101 | + |
|
102 | + my $index = 0; |
|
103 | + foreach my $line ( split( "\n", $log ) ){ |
|
104 | + if ( $line =~ /^\x{feff}?\s*$/ ){ |
|
105 | + next; |
|
106 | + } |
|
107 | +# print $q->h2( ++$index ); |
|
108 | + print $q->start_table( { -border => 1 } ); |
|
109 | +# print $q->Tr( $q->th( 'Line' ), $q->td( $line ) ); |
|
110 | + my( $datetime, $level, $client, $line2 ) = |
|
111 | + ( $line =~ /\[([^\]]+)\]\s\[([^\]]+)\](?:\s\[client\s([^\]]+)\])?\s*(.*)\s*$/ ); |
|
112 | + print $q->Tr( $q->th( 'Date Time' ), $q->td( $datetime ) ); |
|
113 | + print $q->Tr( $q->th( 'Level' ), $q->td( $level ) ); |
|
114 | + if ( $client ){ |
|
115 | + print $q->Tr( $q->th( 'Client' ), $q->td( toHostName( $client ) ) ); |
|
116 | + } |
|
117 | +# print $q->Tr( $q->th( 'Line2' ), $q->td( $line2 ) ); |
|
118 | + foreach my $type ( @pair_type ){ |
|
119 | + if ( $line2 =~ /^$type->{'header'}/ ){ |
|
120 | + my( $summary, $detail ) = ( $1, $2 ); |
|
121 | + $summary =~ s/([\.\,])\s/$1$br/; |
|
122 | + print $q->Tr( $q->th( 'Summary' ), $q->td( decodeURIComponent( $summary ) ) ); |
|
123 | + if ( $detail ){ |
|
124 | + foreach my $pair ( getPair( $type->{'to_pair'}, $type->{'to_keyval'}, $detail ) ){ |
|
125 | + my( $key, $val ) = ( $pair->[0], $pair->[1] ); |
|
126 | + if ( my $proc = $processer{$key} ){ |
|
127 | + $val = $proc->( $val ); |
|
128 | + } |
|
129 | + print $q->Tr( $q->th( $key ), $q->td( $val ) ); |
|
130 | + } |
|
131 | + } |
|
132 | + last; |
|
133 | + } |
|
134 | + } |
|
135 | + print $q->end_table(), $q->br(); |
|
136 | + } |
|
137 | + |
|
138 | + print $q->p( $q->a( { -href => $q->url( -absolute => 1 ) }, 'form' ) ); |
|
139 | +} |
|
140 | + |
|
141 | +sub getPair |
|
142 | +{ |
|
143 | + my( $to_pair, $to_keyval, $line ) = @_; |
|
144 | + my @ret = (); |
|
145 | +# print "'$to_pair'\n'$line'\n"; |
|
146 | + foreach my $pair ( $line =~ /$to_pair/g ){ |
|
147 | +# print "'$pair'\n"; |
|
148 | + my( $key, $val ) = ( $pair =~ /^$to_keyval$/ ); |
|
149 | + $val = decodeURIComponent( $val ); |
|
150 | + push( @ret, [ $key, $val ] ); |
|
151 | + } |
|
152 | + return @ret; |
|
153 | +} |
|
154 | + |
|
155 | +sub print_form |
|
156 | +{ |
|
157 | + print |
|
158 | + $q->start_form( -action => $q->url, -enctype => 'multipart/form-data' ), |
|
159 | + $q->submit, " ", $q->reset, $q->br(), |
|
160 | + $q->textarea( -name=>'LOG', -rows=>20, -columns=>80 ), |
|
161 | + $q->end_form; |
|
162 | +} |
|
163 | + |
|
164 | +sub encodeURIComponent |
|
165 | +{ |
|
166 | + my $str = encode( 'utf-8', shift ); |
|
167 | + $str =~ s/([^0-9A-Za-z!\x27()*\-._~])/sprintf("%%%02X", ord($1))/eg; # \x27 = ' |
|
168 | + return $str; |
|
169 | +} |
|
170 | + |
|
171 | +sub decodeURIComponent |
|
172 | +{ |
|
173 | + my $str = shift; |
|
174 | + $str =~ s/%([0-9A-F][0-9A-F])/pack( "H*", $1 )/egi; |
|
175 | + return decode( 'utf-8', $str ); |
|
176 | +} |
|
177 | + |
|
178 | +sub toHostName |
|
179 | +{ |
|
180 | + my $ip_address = shift || ''; |
|
181 | + my $ret = ''; |
|
182 | + |
|
183 | + my $resolver = Net::DNS::Resolver->new; |
|
184 | + if ( my $ans = $resolver->query( $ip_address ) ){ |
|
185 | + for my $rr ( $ans->answer ){ |
|
186 | + #print $rr->string, "\n"; |
|
187 | + if ( $rr->type eq 'PTR' ){ |
|
188 | + $ret = $rr->ptrdname; |
|
189 | + last; |
|
190 | + } |
|
191 | + } |
|
192 | + } |
|
193 | + |
|
194 | + return $ip_address . '; ' . $ret; |
|
195 | +} |
|
196 | + |
|
197 | +# EOF |
|
198 | +``` |
|
199 | + |
|
200 | +# リンク |
|
201 | +- [[Perl/MatchList]] |
|
202 | +- [[Linux/Apache]] |
|
... | ... | \ No newline at end of file |
Perl/AutoHashedFuncs.md
... | ... | @@ -0,0 +1,76 @@ |
1 | +# AutoHashedFuncs |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- 関数名を指定しなくても関数定義するだけで自動的にハッシュに登録されるサンプル。 |
|
6 | +- 型グロブを使って定義されている関数をスキャンする。 |
|
7 | + |
|
8 | +## ソース |
|
9 | +- [AutoHashedFuncs.zip](AutoHashedFuncs.zip) |
|
10 | +```Perl |
|
11 | +# 関数名を指定しなくても関数定義するだけで自動的にハッシュに登録される。 |
|
12 | + |
|
13 | +use strict; |
|
14 | +use warnings; |
|
15 | +use utf8; |
|
16 | +use Encode; |
|
17 | +use YAML::Syck; |
|
18 | + |
|
19 | +{ |
|
20 | + package MyDecoder; |
|
21 | + |
|
22 | + # 関数へのリファレンスが格納されるハッシュ |
|
23 | + our %Decoders = (); |
|
24 | + |
|
25 | + foreach my $key ( sort( keys( %MyDecoder:: ) ) ){ |
|
26 | + no strict "refs"; |
|
27 | + if ( $key =~ /decode(.*)/ && *{"MyDecoder::$key"}{CODE} ){ |
|
28 | + $Decoders{$1} = *{"MyDecoder::$key"}{CODE}; |
|
29 | + } |
|
30 | + } |
|
31 | + |
|
32 | + # 型グロブからアクセスできるけど CODE ではないので登録されない |
|
33 | + my $decode1 = "aaa"; |
|
34 | + my @decode2 = qw( bbb ccc ddd ); |
|
35 | + our $decode3 = "eee"; |
|
36 | + our @decode4 = qw( fff ggg hhh ); |
|
37 | + |
|
38 | + # 登録される |
|
39 | + sub decodeAdd { |
|
40 | + my( $a, $b ) = @_; |
|
41 | + return $a + $b; |
|
42 | + } |
|
43 | + |
|
44 | + # 登録される |
|
45 | + sub decodeMul { |
|
46 | + my( $a, $b ) = @_; |
|
47 | + return $a * $b; |
|
48 | + } |
|
49 | + |
|
50 | + # 関数名がルールから外れているので登録されない |
|
51 | + sub helper1 { |
|
52 | + my( $a, $b ) = @_; |
|
53 | + return $a - $b; |
|
54 | + } |
|
55 | +} |
|
56 | + |
|
57 | +# $main::refDecoders にリファレンスをコピーして使い易くする |
|
58 | +my $refDecoders = \%MyDecoder::Decoders; |
|
59 | + |
|
60 | +print Dump( $refDecoders ) . "\n"; |
|
61 | + |
|
62 | +for my $key ( qw( decode1 decode2 decode3 decode4 decodeAdd Add decodeMul Mul helper1 ) ){ |
|
63 | + if ( my $dc = $refDecoders->{$key} ){ |
|
64 | + print "$key:\t" . &{$dc}( 2, 4 ) . "\n"; |
|
65 | + } else { |
|
66 | + print "$key:\t-\n"; |
|
67 | + } |
|
68 | +} |
|
69 | + |
|
70 | +# EOF |
|
71 | +``` |
|
72 | + |
|
73 | +## リンク |
|
74 | +- [perldoc.jp](http://perldoc.jp/) / [Perlのリファレンスとネストしたデータ構造](http://perldoc.jp/pod/perlref) |
|
75 | + |
|
76 | +- [サンプルコードによるPerl入門](http://d.hatena.ne.jp/perlcodesample/) / [型グロブとシンボルテーブル](http://d.hatena.ne.jp/perlcodesample/20080614/1213428778) |
|
... | ... | \ No newline at end of file |
Perl/CGI.pm.md
... | ... | @@ -0,0 +1,266 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# 概要 |
|
4 | +- CGI.pm のテストサンプル |
|
5 | +- [動作サンプル](http://www.takeash.net/cgi-bin/etc/testCGI.cgi) |
|
6 | +- フォームタグが閉じていなかったのを修正。(2012/10/02) |
|
7 | + |
|
8 | +# 注意点 |
|
9 | + |
|
10 | +## textfield や hidden などの値を加工してセットしても前の値が表示される |
|
11 | +```perl |
|
12 | +my $param1 = $q->param('param1'); |
|
13 | +++$param1; |
|
14 | +print $param1; |
|
15 | +print $q->textfield( -name => 'param1', -default => $param1 ); # 前の値のまま |
|
16 | +``` |
|
17 | +- 対応方法 |
|
18 | + 1. タグを表示する前に param で値をセットする。 |
|
19 | +```perl |
|
20 | +$q->param( 'param1', $somevalue ); # $q->param( -name => 'param1', -values => [ $somevalue ] ); |
|
21 | +``` |
|
22 | + - [つかのぺ](http://tuka.s12.xrea.com/) / [CGI.pm](http://tuka.s12.xrea.com/index.xcg?p=CGI.pm) |
|
23 | + 1. override を指定すると強制的に上書きできる。 |
|
24 | +```perl |
|
25 | +print $q->textfield( -name => 'param1', -default => $somevalue, -override => 1 ); |
|
26 | +``` |
|
27 | + |
|
28 | +## リストコンテキストでのパラメータ読み出し |
|
29 | +- セキュリティ上の問題のため、リストコンテキストで「$q->param('name')」を使うと警告が表示される。<br />リストコンテキストが必要な場合は代わりに「$q->multi_param('name')」を使う。 |
|
30 | +- [Fetching the value or values of a single named parameter](http://search.cpan.org/dist/CGI/lib/CGI.pod#Fetching_the_value_or_values_of_a_single_named_parameter) |
|
31 | + |
|
32 | +# ソース |
|
33 | +- [testCGI.zip](testCGI.zip) |
|
34 | +```perl |
|
35 | +#!/usr/bin/perl |
|
36 | +# |
|
37 | +# CGI.pm のテスト |
|
38 | + |
|
39 | +use strict; |
|
40 | +use warnings; |
|
41 | +use utf8; |
|
42 | +use Encode; |
|
43 | +use YAML::Syck; |
|
44 | +use CGI::Pretty qw( -no_xhtml *table ); # //HTML 4.01 Transitional//EN |
|
45 | +#use CGI::Carp qw/fatalsToBrowser warningsToBrowser/; |
|
46 | + |
|
47 | +$YAML::Syck::ImplicitUnicode = 1; |
|
48 | + |
|
49 | +binmode( STDIN, ":utf8" ); |
|
50 | +binmode( STDOUT, ":utf8" ); |
|
51 | +binmode( STDERR, ":utf8" ); |
|
52 | + |
|
53 | +my $cginame = 'testCGI'; |
|
54 | +my $cookiename = 'クッキー'; |
|
55 | +my $charset = 'utf-8'; |
|
56 | + |
|
57 | +# フォームのエンコーディングタイプ。 |
|
58 | +# CGI.pm Version 3.48 の param メソッドに影響する。 |
|
59 | +# 1: application/x-www-form-urlencoded, param メソッドでバイナリ文字列が返る。 |
|
60 | +# 0: multipart/form-data, param メソッドで utf8 フラグ付き文字列が返る。 |
|
61 | +my $enctype = 1; |
|
62 | + |
|
63 | +my $q = new CGI; |
|
64 | +$q->charset( $charset ); |
|
65 | + |
|
66 | +my %popupgroup = ( |
|
67 | + 'popup1' => 'ポップアップ1', 'popup2' => 'ポップアップ2', |
|
68 | + 'popup3' => 'ポップアップ3', 'popup4' => 'ポップアップ4', |
|
69 | +); |
|
70 | +my %scrollgroup = ( |
|
71 | + 'scroll1' => 'スクロール1', 'scroll2' => 'スクロール2', |
|
72 | + 'scroll3' => 'スクロール3', 'scroll4' => 'スクロール4', |
|
73 | + 'scroll5' => 'スクロール5', |
|
74 | +); |
|
75 | +my %checkgroup = ( |
|
76 | + 'check1'=>'チェック1', 'check2'=>'チェック2', |
|
77 | + 'check3'=>'チェック3', |
|
78 | +); |
|
79 | +my %radiogroup = ( |
|
80 | + 'radio1'=>'ラジオ1', 'radio2'=>'ラジオ2', |
|
81 | + 'radio3'=>'ラジオ3', |
|
82 | +); |
|
83 | + |
|
84 | +my @names; |
|
85 | +if ( $enctype ){ |
|
86 | + # 'application/x-www-form-urlencoded' |
|
87 | + @names = map{ decode( 'utf8', $_ ) } $q->param(); |
|
88 | +} else { |
|
89 | + # 'multipart/form-data' |
|
90 | + @names = $q->param(); |
|
91 | +} |
|
92 | + |
|
93 | +printHeader(); |
|
94 | + |
|
95 | +if ( @names ){ |
|
96 | + print $q->h2('Param'); |
|
97 | + print $q->start_table( { '-summary' => 'Parameters', '-border' => 1 } ); |
|
98 | + foreach my $name ( @names ){ |
|
99 | + if ( $enctype ){ |
|
100 | + # 'application/x-www-form-urlencoded' |
|
101 | + print $q->Tr( |
|
102 | + $q->th( $name ), |
|
103 | + $q->td( join( $q->br(), map{ decode( 'utf8', $_ ) } $q->param( encode( 'utf8', $name ) ) ) ) |
|
104 | + ); |
|
105 | + } else { |
|
106 | + # 'multipart/form-data' |
|
107 | + print $q->Tr( |
|
108 | + $q->th( $name ), |
|
109 | + $q->td( join( $q->br(), $q->param( $name ) ) ) |
|
110 | + ); |
|
111 | + } |
|
112 | + } |
|
113 | + print $q->end_table(); |
|
114 | + print $q->h2('Cookie'); |
|
115 | + print $q->start_table( { '-summary' => 'Cookie', '-border' => 1 } ); |
|
116 | + foreach my $cookiename ( $q->cookie() ){ |
|
117 | + print $q->Tr( |
|
118 | + $q->th( decode( 'utf8', $cookiename ) ), |
|
119 | + $q->td( join( $q->br(), map{ decode( 'utf8', $_ ) } $q->cookie( $cookiename ) ) ) |
|
120 | + ); |
|
121 | + } |
|
122 | + print $q->end_table(); |
|
123 | +} else { |
|
124 | + print $q->start_form( |
|
125 | + '-action' => $q->url, |
|
126 | + '-enctype' => ( |
|
127 | + ( $enctype ) |
|
128 | + ? 'application/x-www-form-urlencoded' |
|
129 | + : 'multipart/form-data' |
|
130 | + ), |
|
131 | + ); |
|
132 | + print $q->start_table( { '-summary' => 'Parameters', '-border' => 1 } ); |
|
133 | + print $q->Tr( |
|
134 | + $q->th( 'テキスト' ), |
|
135 | + $q->td( $q->textfield( |
|
136 | + '-name' => 'テキスト', |
|
137 | + '-value' => 'あいうえお漢字' |
|
138 | + ) ) |
|
139 | + ); |
|
140 | + print $q->Tr( |
|
141 | + $q->th( 'テキストエリア' ), |
|
142 | + $q->td( $q->textarea( |
|
143 | + '-name' => 'テキストエリア', |
|
144 | + '-default' => "予定表\n\x{20B9F}", |
|
145 | + '-rows' => 3, |
|
146 | + '-columns' => 20 |
|
147 | + ) ) |
|
148 | + ); |
|
149 | + print $q->Tr( |
|
150 | + $q->th( 'ポップアップ' ), |
|
151 | + $q->td( $q->popup_menu( |
|
152 | + '-name' => 'ポップアップ', |
|
153 | + '-values' => [ sort( keys( %popupgroup ) ) ], |
|
154 | + '-default' => ( sort( keys( %popupgroup ) ) )[0], |
|
155 | + '-labels' => \%popupgroup, |
|
156 | + ) ) |
|
157 | + ); |
|
158 | + print $q->Tr( |
|
159 | + $q->th( 'スクロール' ), |
|
160 | + $q->td( $q->scrolling_list( |
|
161 | + '-name' => 'スクロール', |
|
162 | + '-values' => [ sort( keys( %scrollgroup ) ) ], |
|
163 | + '-default' => ( sort( keys( %scrollgroup ) ) )[0], |
|
164 | + '-size' => 3, |
|
165 | + '-multiple' => 'true', |
|
166 | + '-labels' => \%scrollgroup, |
|
167 | + ) ) |
|
168 | + ); |
|
169 | + print $q->Tr( |
|
170 | + $q->th( 'チェックボックス' ), |
|
171 | + $q->td( $q->checkbox_group( |
|
172 | + '-name' => 'チェックボックス', |
|
173 | + '-values' => [ sort( keys( %checkgroup ) ) ], |
|
174 | + '-default' => ( sort( keys( %checkgroup ) ) )[0], |
|
175 | + '-linebreak' => 'true', |
|
176 | + '-labels' => \%checkgroup, |
|
177 | + ) ) |
|
178 | + ); |
|
179 | + print $q->Tr( |
|
180 | + $q->th( 'ラジオボタン' ), |
|
181 | + $q->td( $q->radio_group( |
|
182 | + '-name' => 'ラジオボタン', |
|
183 | + '-values' => [ sort( keys( %radiogroup ) ) ], |
|
184 | + '-default' => ( sort( keys( %radiogroup ) ) )[0], |
|
185 | + '-linebreak' => 'true', |
|
186 | + '-labels' => \%radiogroup, |
|
187 | + ) ) |
|
188 | + ); |
|
189 | + print $q->Tr( $q->td( |
|
190 | + { '-colspan' => 2, '-align' => 'center' }, |
|
191 | + $q->submit . ' ' . $q->reset |
|
192 | + ) ); |
|
193 | + print $q->end_table(); |
|
194 | + print $q->end_form; |
|
195 | +} |
|
196 | + |
|
197 | +printFooter(); |
|
198 | + |
|
199 | +exit; |
|
200 | + |
|
201 | +sub printHeader |
|
202 | +{ |
|
203 | + my $cookieval = decode( 'utf8', |
|
204 | + $q->cookie( encode( 'utf8', $cookiename ) ) || '' |
|
205 | + ); |
|
206 | + $cookieval .= 'あ'; |
|
207 | + my $cookie = $q->cookie( |
|
208 | + '-name' => encode( 'utf8', $cookiename ), |
|
209 | + '-value' => encode( 'utf8', $cookieval ), |
|
210 | + ); |
|
211 | + print $q->header( '-cookie' => [ $cookie ] ); |
|
212 | + print $q->start_html( |
|
213 | + '-title' => $cginame, |
|
214 | + '-lang' => 'ja-JP', |
|
215 | + '-head' => [ |
|
216 | + $q->meta( { '-http_equiv' => 'Content-style-type', '-content' => 'text/css' } ), |
|
217 | + $q->meta( { '-http_equiv' => 'Content-script-type', '-content' => 'text/javascript' } ), |
|
218 | + ], |
|
219 | + '-style' => [ { 'src' => '/take.css' }, ], |
|
220 | + ); |
|
221 | + print $q->h1( $cginame ); |
|
222 | +} |
|
223 | + |
|
224 | +sub printFooter |
|
225 | +{ |
|
226 | + print $q->end_html . "\n"; |
|
227 | +} |
|
228 | + |
|
229 | +# EOF |
|
230 | +``` |
|
231 | + |
|
232 | +# システム設定 |
|
233 | + |
|
234 | +## Windows Server 2012(IIS8) |
|
235 | +- IIS インストール時に、「CGI」「ISAPI 拡張」「要求フィルター」を有効にする。 |
|
236 | + - IPアドレスによるアクセス制限を行う場合は「IPおよびドメインの制限」も有効にする。 |
|
237 | +- IIS マネージャ |
|
238 | + - 「アプリケーションプール - DefaultAppPool - 詳細設定 - 32ビットアプリケーションの有効化」を「True」に設定する。 |
|
239 | + - 「Default Web Site」または該当フォルダ |
|
240 | + - 「ハンドラーマッピング」を開き、「スクリプトマップ」を追加する。 |
|
241 | +| 要求パス | *.cgi | |
|
242 | +| --- | --- | |
|
243 | +| 実行可能ファイル | C:\Perl\bin\perlis.dll | |
|
244 | +| 名前 | Perl CGI | |
|
245 | + - 「既定のドキュメント」を開き、「index.cgi」を追加する。 |
|
246 | + - 「要求フィルター」のアップロード許可最大サイズの既定値は30MB弱。 |
|
247 | + - 最大値を変更する場合は、「要求フィルター」から、「機能設定の編集」を開き、「許可されたコンテンツ最大長」を変更する。 |
|
248 | + - [IIS で要求フィルタリングを構成する](http://technet.microsoft.com/ja-jp/library/hh831621.aspx) |
|
249 | + - [要求フィルターの使用方法](http://technet.microsoft.com/ja-jp/library/dd939071.aspx) |
|
250 | + - [要求制限 <requestLimits>](http://technet.microsoft.com/ja-jp/library/ee431638.aspx) |
|
251 | + |
|
252 | +- Active Perl は 32bit 版をインストールする。 |
|
253 | + - 64bit 版は、「perlis.dll」が含まれていない。 |
|
254 | + - CGI.pm でのアップロードサイズ制限設定は $CGI::POST_MAX で行う。 |
|
255 | + |
|
256 | +# リンク |
|
257 | +- [[Perl/環境変数]] |
|
258 | + |
|
259 | +- [CPAN:CGI-Alternatives](http://search.cpan.org/dist/CGI-Alternatives) |
|
260 | +- [CPAN:Mojolicious](http://search.cpan.org/dist/Mojolicious) |
|
261 | + - [CPAN:Mojolicious/lib/Mojolicious/Lite.pm](http://search.cpan.org/dist/Mojolicious/lib/Mojolicious/Lite.pm) |
|
262 | + |
|
263 | +- [CPAN:CGI](http://search.cpan.org/dist/CGI) |
|
264 | +- [CPAN:Encode](http://search.cpan.org/dist/Encode) |
|
265 | + |
|
266 | +- [perl - use CGI; use Encode; # 非英語Webプログラミング3原則](http://blog.livedoor.jp/dankogai/archives/51227060.html) |
|
... | ... | \ No newline at end of file |
Perl/CPAN.md
... | ... | @@ -0,0 +1,169 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# CPAN |
|
4 | +## シェルを起動して対話的にインストール |
|
5 | +``` |
|
6 | +# perl -MCPAN -e shell |
|
7 | +``` |
|
8 | + |
|
9 | +## bash 等からインストール |
|
10 | +``` |
|
11 | +# perl -MCPAN -e "CPAN::Shell->install('Bundle::CPAN')" |
|
12 | +``` |
|
13 | + |
|
14 | +## 更新可能なパッケージ一覧の表示 |
|
15 | +``` |
|
16 | +# perl -MCPAN -e "CPAN::Shell->r" |
|
17 | +``` |
|
18 | + |
|
19 | +## 一括更新 |
|
20 | +``` |
|
21 | +# perl -MCPAN -e "CPAN::Shell->install(CPAN::Shell->r)" |
|
22 | +``` |
|
23 | +- 途中で Yes/No の確認を求められる。 |
|
24 | + |
|
25 | +## バージョンを指定してインストール |
|
26 | +``` |
|
27 | +# perl -MCPAN -e "CPAN::Shell->install('LEMBARK/FindBin-libs-1.55.tar.gz')" |
|
28 | +``` |
|
29 | +- [CPAN:FindBin-libs](http://search.cpan.org/dist/FindBin-libs) は Perl v5.10.0 以上が必要で v5.8.8 にはインストールできない。 |
|
30 | + |
|
31 | +## シェルでヒストリが効かない (Bundle::CPANをインストール) |
|
32 | +``` |
|
33 | +> install Bundle::CPAN |
|
34 | +``` |
|
35 | + |
|
36 | +## 強制的に再インストール |
|
37 | +- インストール済みであっても強制に再インストールするには「force」を付ける。 |
|
38 | +``` |
|
39 | +> force install Scalar::Util |
|
40 | +``` |
|
41 | +- 「IO::Socket::SSL」が下記エラーにてインストールできなかったら、依存する「Scalar::Util」を強制再インストールする。 |
|
42 | +``` |
|
43 | +Net::SSL from Crypt-SSLeay can't verify hostnames; either install IO::Socket::SSL or turn off verification by setting the PERL_LWP_SSL_VERIFY_HOSTNAME environment variable to 0 at /usr/lib/perl5/site_perl/5.8.8/LWP/Protocol/http.pm line 51. |
|
44 | +``` |
|
45 | +  |
|
46 | +``` |
|
47 | +You need the XS Version of Scalar::Util for dualvar() support at Makefile.PL line 56. |
|
48 | +``` |
|
49 | + |
|
50 | +## 複数のパッケージをまとめてインストール |
|
51 | +- インストールしたいパッケージ名を書いた適当な *.pm ファイルを作成し、それをインストールする。 |
|
52 | +``` |
|
53 | +# cd ~ |
|
54 | +# perl -MCPAN -e "CPAN::Shell->install('Bundle::MyPackages')" |
|
55 | +``` |
|
56 | +- /root/Bundle/MyPackages.pm |
|
57 | +```perl |
|
58 | +package Bundle::MyPackages; |
|
59 | + |
|
60 | +use strict; |
|
61 | +use utf8; |
|
62 | +use vars qw( $VERSION ); |
|
63 | +$VERSION = "0.01"; |
|
64 | +1; |
|
65 | + |
|
66 | +=head1 CONTENTS |
|
67 | + |
|
68 | +Env |
|
69 | +Fatal |
|
70 | +Test::Warnings |
|
71 | +Test::Output |
|
72 | +Test::Deep |
|
73 | +Time::Piece |
|
74 | +CGI |
|
75 | +URI::Escape::XS |
|
76 | +File::Basename |
|
77 | +FindBin::libs |
|
78 | +Getopt::Long |
|
79 | +HTTP::Date |
|
80 | +JSON::XS |
|
81 | +Lingua::JA::Numbers |
|
82 | +Lingua::JA::Regular::Unicode |
|
83 | +Log::Dispatch |
|
84 | +MIME::Base64 |
|
85 | +Socket |
|
86 | +Net::IP |
|
87 | +Net::Wake |
|
88 | +Crypt::SSLeay |
|
89 | +Perl::Tidy |
|
90 | +String::Util |
|
91 | +Text::CSV_XS |
|
92 | +Text::xSV::Slurp |
|
93 | +XML::Simple |
|
94 | +XML::XPath |
|
95 | +enum::hash |
|
96 | +Attribute::Constant |
|
97 | +Number::Format |
|
98 | +PadWalker |
|
99 | +Term::Encoding |
|
100 | + |
|
101 | +=cut |
|
102 | +``` |
|
103 | +- [複数のCPANモジュールを一括インストール - Kawa.net 旧ゆうすけブログ (Yahoo!版)](http://blogs.yahoo.co.jp/kawa_kawa_kawa_kawa/650645.html) |
|
104 | + |
|
105 | +## インストール済みのモジュールのバージョン確認 |
|
106 | +- Linux |
|
107 | +``` |
|
108 | +# perl -M(モジュール名) -e 'print "$(モジュール名)::VERSION\n";' |
|
109 | +# perl -MJSON::Syck -e 'print "$JSON::Syck::VERSION\n";' |
|
110 | +``` |
|
111 | +- Win |
|
112 | +``` |
|
113 | +> perl -M(モジュール名) -e "print $(モジュール名)::VERSION;" |
|
114 | +> perl -MJSON::Syck -e "print $JSON::Syck::VERSION;" |
|
115 | +``` |
|
116 | + |
|
117 | +# cpanminus |
|
118 | +## インストール |
|
119 | +- yum |
|
120 | +``` |
|
121 | +# yum install perl-App-cpanminus |
|
122 | +``` |
|
123 | +- CPAN |
|
124 | +``` |
|
125 | +# perl -MCPAN -e "CPAN::Shell->install('App::cpanminus')" |
|
126 | +# cpanm App::cpanoutdated |
|
127 | +``` |
|
128 | + |
|
129 | +## cpanm 自身のアップグレード |
|
130 | +``` |
|
131 | +# cpanm --self-upgrade |
|
132 | +``` |
|
133 | + |
|
134 | +## 一括更新 |
|
135 | +``` |
|
136 | +# cpan-outdated | cpanm |
|
137 | +``` |
|
138 | + |
|
139 | +# ppm |
|
140 | +## 一括更新 |
|
141 | +``` |
|
142 | +> ppm upgrade --install |
|
143 | +``` |
|
144 | + |
|
145 | +## 複数のパッケージをまとめてインストール |
|
146 | +- パッケージを複数指定する。 |
|
147 | +``` |
|
148 | +> ppm install Env Fatal Test::Warnings Test::Output Test::Deep Time::Piece |
|
149 | +> ppm install CGI URI::Escape::XS File::Basename FindBin::libs Getopt::Long |
|
150 | +> ppm install HTTP::Date JSON::XS Lingua::JA::Numbers Lingua::JA::Regular::Unicode |
|
151 | +> ppm install Log::Dispatch MIME::Base64 Socket Net::IP Net::Wake Crypt::SSLeay Perl::Tidy |
|
152 | +> ppm install String::Util Text::CSV_XS Text::xSV::Slurp XML::Simple XML::XPath |
|
153 | +> ppm install enum::hash Attribute::Constant Number::Format PadWalker Term::Encoding |
|
154 | +``` |
|
155 | + |
|
156 | +# リンク |
|
157 | +- [CPAN:CPAN/lib/CPAN.pm](http://search.cpan.org/dist/CPAN/lib/CPAN.pm) |
|
158 | + |
|
159 | +- [CPAN:App-cpanminus](http://search.cpan.org/dist/App-cpanminus) |
|
160 | +- https://github.com/miyagawa/cpanminus |
|
161 | +- [perl-App-cpanminus](http://rpm.pbone.net/index.php3?stat=3&search=perl-App-cpanminus&srodzaj=3) |
|
162 | + |
|
163 | +- [CPAN:Module-CoreList/lib/Module/CoreList.pod](http://search.cpan.org/dist/Module-CoreList/lib/Module/CoreList.pod) |
|
164 | +- [$shibayu36->blog;](http://shibayu36.hatenablog.com/) |
|
165 | + - [perlであるモジュールがコアモジュールかどうか調べる;](http://shibayu36.hatenablog.com/entry/2014/03/08/115105) |
|
166 | + |
|
167 | +- [CPAN:ExtUtils-Install/lib/ExtUtils/Installed.pm](http://search.cpan.org/dist/ExtUtils-Install/lib/ExtUtils/Installed.pm) |
|
168 | +- [Using Perl](http://nozawashinichi.sakura.ne.jp/usingmt/) |
|
169 | + - [Perl インストールされているモジュールを出力するコマンド](http://nozawashinichi.sakura.ne.jp/usingmt/2014/03/perl-8.html) |
|
... | ... | \ No newline at end of file |
Perl/DBIx-Custom.md
... | ... | @@ -0,0 +1,177 @@ |
1 | +# DBIx::Custom |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- [CPAN:DBIx-Custom](http://search.cpan.org/dist/DBIx-Custom) を使用して MS SQL Server に対してクエリを実行するサンプル。 |
|
6 | +- Where 句に「:UserID{=}」とか付け加えたいとこだけど、「$dbi->not_exists」がうまく働いてなくて値無しだとハングアップするみたいだ。 |
|
7 | +- というか MS SQL Server の ODBC はハングアップし過ぎ。ちゃんとエラー出して止まってくれ。 |
|
8 | + |
|
9 | +## ソース |
|
10 | +- [DBIx-Custom.zip](DBIx-Custom.zip) |
|
11 | + |
|
12 | +### summarize.pl |
|
13 | +```perl |
|
14 | +#!/usr/bin/perl |
|
15 | +# DBIx::Custom サンプル |
|
16 | +# 注文履歴集計 MS SQL Server 用 |
|
17 | + |
|
18 | +use strict; |
|
19 | +use warnings; |
|
20 | +use utf8; |
|
21 | +use Encode; |
|
22 | +use YAML::Syck; |
|
23 | +use DBIx::Custom; |
|
24 | +use DateTime; |
|
25 | +use Text::xSV::Slurp qw( xsv_slurp ); |
|
26 | + |
|
27 | +$YAML::Syck::ImplicitUnicode = 1; |
|
28 | + |
|
29 | +my $charsetConsole = 'CP932'; |
|
30 | +#my $charsetFile = 'UTF-8'; |
|
31 | +my $charsetFile = 'CP932'; |
|
32 | + |
|
33 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
34 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
35 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
36 | + |
|
37 | +my $DB_Connect_yaml = './DB_Connect.yaml'; |
|
38 | +my $fnOders = './DB/Orders.txt'; |
|
39 | + |
|
40 | +my $start_date = '2012-08-20'; |
|
41 | +my $end_date = '2012-09-01'; |
|
42 | + |
|
43 | +my $DB_Connect = YAML::Syck::LoadFile( $DB_Connect_yaml ) |
|
44 | + or die( "$DB_Connect_yaml: $!\n" ); |
|
45 | +foreach( %{$DB_Connect} ){ |
|
46 | + $DB_Connect->{'DSN'} =~ s/_${_}_/$DB_Connect->{$_}/; |
|
47 | +} |
|
48 | + |
|
49 | +my $dbi = DBIx::Custom->connect( |
|
50 | + dsn => 'DBI:' . $DB_Connect->{'DSN'}, |
|
51 | + user => $DB_Connect->{'User'}, |
|
52 | + password => $DB_Connect->{'Password'}, |
|
53 | + option => $DB_Connect->{'Options'} |
|
54 | +); |
|
55 | + |
|
56 | +#insertOrderRandom(); |
|
57 | +#insertOrderFromFile(); |
|
58 | + |
|
59 | +my $Orders = getOrders( $start_date, $end_date ); |
|
60 | +print Dump( $Orders ); |
|
61 | +exit; |
|
62 | + |
|
63 | +sub getOrders |
|
64 | +{ |
|
65 | + my( $start_date, $end_date ) = @_; |
|
66 | + |
|
67 | + my $where = $dbi->where; |
|
68 | + $where->clause( [ 'and', ':OrderDateTime{>=}', ':OrderDateTime{<}' ] ); |
|
69 | + $where->param({ |
|
70 | + OrderDateTime => [ |
|
71 | + $start_date ? $start_date : '1900-01-01', # $dbi->not_exists だとハングアップする? |
|
72 | + $end_date ? $end_date : '9999-12-31', # $dbi->not_exists だとハングアップする? |
|
73 | + ], |
|
74 | + }); |
|
75 | + |
|
76 | + my $sortOrder = $dbi->order; |
|
77 | + $sortOrder->prepend( 'UserID', 'OrderDateTime' ); |
|
78 | + |
|
79 | + my $Orders = $dbi->select( |
|
80 | + table => 'Orders', |
|
81 | + column => [ |
|
82 | + '[Orders].[OrderDateTime]', '[Orders].[OrderQuantity]', # Orders |
|
83 | + '[Users].[UserID]', '[Users].[UserName]', # Users |
|
84 | + '[Items].[ItemName]', '[Items].[ItemUnitPrice]', # Items |
|
85 | + '[Items].[ItemUnitPrice] * [Orders].[OrderQuantity] as [SubTotalPrice]', # 追加計算 |
|
86 | + ], |
|
87 | + join => [ |
|
88 | + 'JOIN [Users] ON [Orders].[OrderUser] = [Users].[UserID]', |
|
89 | + 'JOIN [Items] ON [Orders].[OrderItem] = [Items].[ItemID]', |
|
90 | + ], |
|
91 | + where => $where, |
|
92 | + append => $sortOrder->to_string, |
|
93 | + )->all; |
|
94 | + |
|
95 | + return $Orders; |
|
96 | +} |
|
97 | + |
|
98 | +sub insertOrderRandom |
|
99 | +{ |
|
100 | + my $userMax = 5; |
|
101 | + my $itemMax = 7; |
|
102 | + my $quantityMax = 30; |
|
103 | + for( my $orderNum = 20; $orderNum > 0; --$orderNum ){ |
|
104 | + my $datetime = DateTime->new( |
|
105 | + time_zone => 'local', |
|
106 | + year => 2012, |
|
107 | + month => int( rand( 4 ) + 7 ), |
|
108 | + day => int( rand( 31 ) + 1 ), |
|
109 | + hour => int( rand( 10 ) + 9 ), |
|
110 | + minute => int( rand( 60 ) ), |
|
111 | + ); |
|
112 | + $dbi->insert( |
|
113 | + { |
|
114 | + OrderDateTime => $datetime->ymd('-') . ' ' . $datetime->hms(':'), |
|
115 | + OrderUser => int( rand( $userMax ) + 1 ), |
|
116 | + OrderItem => int( rand( $itemMax ) + 1 ), |
|
117 | + OrderQuantity => int( rand( $quantityMax ) + 1 ), |
|
118 | + }, |
|
119 | + table => 'Orders', |
|
120 | + ); |
|
121 | + } |
|
122 | +} |
|
123 | + |
|
124 | +sub insertOrderFromFile |
|
125 | +{ |
|
126 | + my @orders = readXSV( $fnOders, { sep_char => "\t" } ); |
|
127 | + foreach my $order ( @orders ){ |
|
128 | + delete $order->{'OrderID'}; # IDENTITY 列を追加しようとするとハングアップする。 |
|
129 | + $dbi->insert( |
|
130 | + $order, |
|
131 | + table => 'Orders', |
|
132 | + ); |
|
133 | + } |
|
134 | +} |
|
135 | + |
|
136 | +sub readXSV |
|
137 | +{ |
|
138 | + my( $fname, $opt ) = @_; |
|
139 | + $opt = { binary => 1, %{$opt} }; |
|
140 | + open( my $fhin, "<:encoding($charsetFile)", encode( $charsetConsole, $fname ) ) |
|
141 | + or die( "$fname: $!" ); |
|
142 | + my @body = <$fhin>; |
|
143 | + close( $fhin ); |
|
144 | + my $ret = xsv_slurp( |
|
145 | + string => join( "", @body ), |
|
146 | + text_csv => $opt, |
|
147 | + ); |
|
148 | + return ( ref( $ret ) eq 'ARRAY' ) |
|
149 | + ? @{ $ret } |
|
150 | + : $ret ; |
|
151 | +} |
|
152 | + |
|
153 | +# EOF |
|
154 | +``` |
|
155 | + |
|
156 | +### DB_Connect.yaml |
|
157 | +``` |
|
158 | +# DB接続情報 |
|
159 | +Driver: ODBC |
|
160 | +Server: localhost\SQLExpress,1433 # <サーバ名>\<インスタンス名>[,<ポート番号>] |
|
161 | +User: TestUser |
|
162 | +Password: "TestPass" # 記号を含む場合は""で括る。 |
|
163 | +DB: TestShop1 |
|
164 | +Trusted_Connection: No |
|
165 | +AutoTranslate: No |
|
166 | +Options: |
|
167 | + LongTruncOk: 1 |
|
168 | + LongReadLen: 8192 |
|
169 | +DSN: _Driver_:Driver={SQL Server}; Server={_Server_}; Database=_DB_; Trusted_Connection=_Trusted_Connection_; AutoTranslate=_AutoTranslate_; |
|
170 | +``` |
|
171 | + |
|
172 | +## リンク |
|
173 | +- [[DBIx::NamedParams|Perl/DBIx-NamedParams]] |
|
174 | + |
|
175 | +- [CPAN:DBIx-Custom](http://search.cpan.org/dist/DBIx-Custom) |
|
176 | + - [CPAN:DBIx-Custom/lib/DBIx/Custom/Where.pm](http://search.cpan.org/dist/DBIx-Custom/lib/DBIx/Custom/Where.pm) |
|
177 | + - [CPAN:DBIx-Custom/lib/DBIx/Custom/Order.pm](http://search.cpan.org/dist/DBIx-Custom/lib/DBIx/Custom/Order.pm) |
|
... | ... | \ No newline at end of file |
Perl/DBIx-NamedParams.md
... | ... | @@ -0,0 +1,825 @@ |
1 | +# DBIx::NamedParams |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- mysql でも prepare でプレースホルダとして ? じゃなく名前で指定できるようにする。 |
|
6 | +- 同じ名前を繰り返し使ってもエラーにならない。 |
|
7 | +- こっちより [CPAN:DBIx-Custom](http://search.cpan.org/dist/DBIx-Custom) の方が柔軟で高機能だなー。どうしたもんか。 |
|
8 | +- [CPAN:DBIx-NamedBinding](http://search.cpan.org/dist/DBIx-NamedBinding) に比べると、bind_param_ex の1回でバインドできるのと型指定できる点が勝ってるかな。 |
|
9 | + |
|
10 | +## 使用法 |
|
11 | +### スカラーのバインド |
|
12 | +- 「:名前-型」でスカラー値を bind する。 |
|
13 | +```perl |
|
14 | +my $sql_insert = qq{ |
|
15 | + INSERT INTO `Users` ( `ID`, `Name`, `Status`, `RegDate` ) |
|
16 | + VALUES ( NULL, :Name-VARCHAR, :State-INTEGER, :RegDate-DATETIME ); |
|
17 | +}; |
|
18 | +$sth_insert = $dbh->prepare_ex( $sql_insert ) or die( "$DBI::errstr\n" ); |
|
19 | +$sth_insert->bind_param_ex( { 'Name' => 'リオ', 'State' => 1, 'RegDate' => '2011-02-21 10:00' } ); |
|
20 | +$sth_insert->execute() or die( "$DBI::errstr\n" ); |
|
21 | +``` |
|
22 | + |
|
23 | +### 配列(個数指定あり)のバインド |
|
24 | +- 「:名前{個数}-型」で配列値を個数個分 bind する。 |
|
25 | +```perl |
|
26 | +my $sql_select = qq{ |
|
27 | + SELECT `ID`, `Name`, `Status`, `RegDate` |
|
28 | + FROM `Users` |
|
29 | + WHERE `Status` in ( :State{4}-INTEGER ); |
|
30 | +}; |
|
31 | +$sth_select = $dbh->prepare_ex( $sql_select ) or die( "$DBI::errstr\n" ); |
|
32 | +$sth_select->bind_param_ex( { 'State' => [ 1,2,4,8 ] } ); |
|
33 | +$sth_select->execute() or die( "$DBI::errstr\n" ); |
|
34 | +``` |
|
35 | + |
|
36 | +### 配列(個数指定なし)のバインド |
|
37 | +- 「:名前+-型」で配列値を配列要素個分 bind する。<br /> |
|
38 | +prepare_exの引数としてSQL文と共に割り当てるハッシュを指定する必要がある。 |
|
39 | +```perl |
|
40 | +my $sql_select = qq{ |
|
41 | + SELECT `ID`, `Name`, `Status`, `RegDate` |
|
42 | + FROM `Users` |
|
43 | + WHERE `Status` in ( :State+-INTEGER ); |
|
44 | +}; |
|
45 | +$sth_select = $dbh->prepare_ex( $sql_select, { 'State' => [ 1,2,4,8 ] } ) |
|
46 | + or die( "$DBI::errstr\n" ); |
|
47 | +$sth_select->execute() or die( "$DBI::errstr\n" ); |
|
48 | +``` |
|
49 | + |
|
50 | +### デバッグログの採取 |
|
51 | +- プレースホルダの解析結果、解析後の SQL 文、バインドされる値をログファイルに書き出します。 |
|
52 | +- ファイル名を省略すると、ホームディレクトリ(Linux: 環境変数 HOME, Windows: 環境変数 USERPROFILE)にログファイル(DBIx-NamedParams.log)が作られます。 |
|
53 | +``` |
|
54 | +DBIx::NamedParams::debug_log( 'testNamedParams.log' ); |
|
55 | +``` |
|
56 | + |
|
57 | +### DBD のデータタイプに対応する SQL タイプのハッシュ |
|
58 | +``` |
|
59 | +my %DrvTypeToSQLType = $dbh->driver_typename_map(); |
|
60 | +``` |
|
61 | +- [[MySQL の例|#MySQL_DataType_Map]] |
|
62 | +- [[MS SQL Server の例|#MSSQL_DataType_Map]] |
|
63 | + |
|
64 | +## 変更履歴 |
|
65 | +### 0.0.5 / 2011/09/28 |
|
66 | +- driver_typename_map メソッドが返すハッシュを調整。DB が MS SQL Server の場合、datetime および smalldatetime に対して DATE ではなく WVARCHAR を割り当てるようにした。 |
|
67 | + |
|
68 | +### 0.0.4 / 2011/09/17 |
|
69 | +- driver_typename_map メソッド追加。その DBD で使用できるデータタイプに対応する SQL タイプ名のハッシュを返す。 |
|
70 | +- デバッグログのファイル名を指定できるようにした。ログの体裁の調整。 |
|
71 | +- MS SQL Server 版のサンプルを作成。datetime 型にバインドするのに DATETIME じゃなくて WVARCHAR(VARCHAR) 使わなくちゃいけないなんて、そんなん考慮しとらんよ…。 |
|
72 | + |
|
73 | +### 0.0.3 / 2011/04/17 |
|
74 | +- 機能面での追加・変更はなし。 |
|
75 | +- 「use base;」を「use parent;」に変更。 |
|
76 | +- import にて、継承元である DBI の import を呼び出すようにしたけど、不要かも? |
|
77 | +- ソース内の関数の順序を呼び出し元と呼び出し先が近くになるように変更。 |
|
78 | +- _parse_ex にて、$repeat の既定値を '' から 0 に変更。 |
|
79 | +- bind_param_ex にて、「no warnings;」を「no warnings 'uninitialized';」に変更。 |
|
80 | +- bind_param_ex にて、$ref_hash が HASH であることを確認するようにした。 |
|
81 | + |
|
82 | +### 0.0.2 / 2011/03/07 |
|
83 | +- prepare_ex のときに @_NamedParams をクリアするようにした。 |
|
84 | + |
|
85 | +## ソース |
|
86 | +- [NamedParams.zip](NamedParams.zip) |
|
87 | + |
|
88 | +### NamedParams.pm |
|
89 | +```perl |
|
90 | +# DBI::db::prepare, DBI::st::bind_param を拡張する。 |
|
91 | +# http://www.TakeAsh.net/wiki/?Perl/DBIx-NamedParams |
|
92 | +# |
|
93 | +# prepare_ex では「:名前-型」形式のようにプレースホルダを書く。 |
|
94 | +# bind_param_ex では名前と値の対応を示すハッシュを渡す。 |
|
95 | + |
|
96 | +package DBIx::NamedParams; |
|
97 | + |
|
98 | +use strict; |
|
99 | +use warnings; |
|
100 | +use utf8; |
|
101 | +use Encode; |
|
102 | +use Carp qw( croak ); |
|
103 | +use parent qw( DBI ); |
|
104 | +use DBI::Const::GetInfoType; |
|
105 | +use Log::Dispatch; |
|
106 | +use POSIX qw( strftime ); |
|
107 | + |
|
108 | +use version; our $VERSION = qv( '0.0.5' ); |
|
109 | + |
|
110 | +( $ENV{'LANG'} || '' ) =~ /\.(.*)$/; # ja_JP.UTF-8 |
|
111 | +my $charsetConsole = $1 || 'CP932'; |
|
112 | +my $charsetFile = 'UTF-8'; |
|
113 | + |
|
114 | +my $_default_log_filename = ( $ENV{'HOME'} || $ENV{'USERPROFILE'} ); |
|
115 | +$_default_log_filename =~ s#\\#/#g; |
|
116 | +$_default_log_filename .= '/DBIx-NamedParams.log'; |
|
117 | + |
|
118 | +my %_SQL_TypeRefs = (); |
|
119 | +my %_SQL_TypeInvs = (); |
|
120 | +my $_SQL_Types = ""; |
|
121 | +my @_NamedParams = (); |
|
122 | +my $_index; |
|
123 | +my $_log = undef; |
|
124 | + |
|
125 | +sub import { |
|
126 | + DBI->import(); # 不要か? |
|
127 | + _init(); |
|
128 | + *{DBI::db::driver_typename_map} = \&driver_typename_map; |
|
129 | + *{DBI::db::prepare_ex} = \&prepare_ex; |
|
130 | + *{DBI::st::bind_param_ex} = \&bind_param_ex; |
|
131 | +} |
|
132 | + |
|
133 | +sub _init |
|
134 | +{ |
|
135 | + foreach( @{ $DBI::EXPORT_TAGS{sql_types} } ){ |
|
136 | + my $refFunc = \&{"DBI::$_"}; |
|
137 | + if ( /^SQL_(.*)$/i ){ |
|
138 | + $_SQL_TypeRefs{ $1 } = &{ $refFunc }; |
|
139 | + $_SQL_TypeInvs{ &{ $refFunc } } = $1; |
|
140 | + } |
|
141 | + } |
|
142 | + $_SQL_Types = all_sql_types(); |
|
143 | +} |
|
144 | + |
|
145 | +sub debug_log |
|
146 | +{ |
|
147 | + my( $filename ) = @_; |
|
148 | + $filename = encode( $charsetConsole, ( $filename || $_default_log_filename ) ); |
|
149 | + $_log = Log::Dispatch->new( |
|
150 | + outputs => [ [ |
|
151 | + 'File', |
|
152 | + min_level => 'debug', |
|
153 | + filename => $filename, |
|
154 | + binmode => ":encoding($charsetFile)", |
|
155 | + permissions => 0666, |
|
156 | + newline => 1, |
|
157 | + ], ], |
|
158 | + ); |
|
159 | + $_log->info( _thisFuncName(), strftime( "%Y-%m-%d %H:%M:%S", localtime ) ); |
|
160 | +} |
|
161 | + |
|
162 | +sub _thisFuncName |
|
163 | +{ |
|
164 | + ( caller( 1 ) )[3] =~ /([^:]+)$/; |
|
165 | + return $1; |
|
166 | +} |
|
167 | + |
|
168 | +sub all_sql_types |
|
169 | +{ |
|
170 | + return wantarray |
|
171 | + ? sort( keys( %_SQL_TypeRefs ) ) |
|
172 | + : join( "|", sort( keys( %_SQL_TypeRefs ) ) ); |
|
173 | +} |
|
174 | +sub driver_typename_map |
|
175 | +{ |
|
176 | + my( $self ) = @_; |
|
177 | + my %map = (); |
|
178 | + foreach my $refType ( $self->type_info() ){ |
|
179 | + my $datatype = $refType->{ 'SQL_DATA_TYPE' } # MS SQL Server |
|
180 | + || $refType->{ 'SQL_DATATYPE' }; # MySQL |
|
181 | + $map{ $refType->{ 'TYPE_NAME' } } = $_SQL_TypeInvs{ $datatype } || 'WVARCHAR'; |
|
182 | + } |
|
183 | + if ( $self->get_info( $GetInfoType{ 'SQL_DBMS_NAME' } ) eq 'Microsoft SQL Server' ){ |
|
184 | + $map{ 'datetime' } = 'WVARCHAR'; |
|
185 | + $map{ 'smalldatetime' } = 'WVARCHAR'; |
|
186 | + } |
|
187 | + return %map; |
|
188 | +} |
|
189 | + |
|
190 | +sub prepare_ex |
|
191 | +{ |
|
192 | + my( $self, $sqlex, $refHash ) = @_; |
|
193 | + my $ret = undef; |
|
194 | + my $validHash = defined( $refHash ) && ref( $refHash ) eq 'HASH'; |
|
195 | + if ( $sqlex =~ /\:([\w]+)\+-($_SQL_Types)\b/ ){ |
|
196 | + if ( $validHash ){ |
|
197 | + $sqlex =~ s/\:([\w]+)\+-($_SQL_Types)\b/_parse_ex1($refHash,$1,$2);/ge; |
|
198 | + } else { |
|
199 | + croak( "prepare_ex need a hash reference when SQL is variable length.\n" ); |
|
200 | + } |
|
201 | + } |
|
202 | + @_NamedParams = (); |
|
203 | + $_index = 1; |
|
204 | + $sqlex =~ s/\:([\w]+)(?:\{(\d+)\})?-($_SQL_Types)\b/_parse_ex2($1,$2,$3);/ge; |
|
205 | + if ( $_log ){ |
|
206 | + $_log->info( _thisFuncName(), 'sql_raw', "{{$sqlex}}" ); |
|
207 | + } |
|
208 | + $ret = $self->prepare( $sqlex ) or croak( "$DBI::errstr" ); |
|
209 | + if ( $validHash ){ |
|
210 | + $ret->bind_param_ex( $refHash ); |
|
211 | + } |
|
212 | + return $ret; |
|
213 | +} |
|
214 | + |
|
215 | +sub _parse_ex1 |
|
216 | +{ |
|
217 | + my( $refHash, $name, $type ) = @_; |
|
218 | + return ":${name}{" . scalar( @{ $refHash->{ $name } } ) . "}-$type"; |
|
219 | +} |
|
220 | + |
|
221 | +sub _parse_ex2 |
|
222 | +{ |
|
223 | + my $name = shift || ''; |
|
224 | + my $repeat = shift || 0; |
|
225 | + my $type = shift || ''; |
|
226 | + my $ret = ''; |
|
227 | + # '' や 0 も有効値として使いたい場合 (Perl 5.9 以降) |
|
228 | + # my $param = shift // -1; |
|
229 | + if ( $_log ){ |
|
230 | + $_log->info( |
|
231 | + _thisFuncName(), |
|
232 | + "[$_index]", |
|
233 | + "\"$name\"", |
|
234 | + (!$repeat) ? "scalar" : "array[$repeat]", |
|
235 | + $type |
|
236 | + ); |
|
237 | + } |
|
238 | + if ( !$repeat ){ |
|
239 | + # scalar |
|
240 | + $_NamedParams[ $_index++ ] = { |
|
241 | + Name => $name, |
|
242 | + Type => $_SQL_TypeRefs{ $type }, |
|
243 | + Array => -1, |
|
244 | + }; |
|
245 | + $ret = '?'; |
|
246 | + } else { |
|
247 | + # array |
|
248 | + for( my $i=0; $i<$repeat; ++$i ){ |
|
249 | + $_NamedParams[ $_index++ ] = { |
|
250 | + Name => $name, |
|
251 | + Type => $_SQL_TypeRefs{ $type }, |
|
252 | + Array => $i, |
|
253 | + }; |
|
254 | + } |
|
255 | + $ret = substr( '?,' x $repeat, 0, -1 ); |
|
256 | + } |
|
257 | + return $ret; |
|
258 | +} |
|
259 | + |
|
260 | +sub bind_param_ex |
|
261 | +{ |
|
262 | + no warnings 'uninitialized'; |
|
263 | + my( $self, $refHash ) = @_; |
|
264 | + if ( !defined( $refHash ) || ref( $refHash ) ne 'HASH' ){ |
|
265 | + croak( "bind_param_ex need a hash reference.\n" ); |
|
266 | + } |
|
267 | + my $thisFunc = _thisFuncName(); |
|
268 | + for( my $i=1; $i<@_NamedParams; ++$i ){ |
|
269 | + my $idx = $_NamedParams[ $i ]{ 'Array' }; |
|
270 | + my $value1 = $refHash->{ $_NamedParams[ $i ]{ 'Name' } }; |
|
271 | + my $value2 = ( $idx < 0 || ref( $value1 ) ne 'ARRAY' ) |
|
272 | + ? $value1 |
|
273 | + : @{ $value1 }[ $idx ]; |
|
274 | + my $datatype = $_NamedParams[ $i ]{ 'Type' }; |
|
275 | + if ( $_log ){ |
|
276 | + $_log->info( |
|
277 | + $thisFunc, "[$i]", "\"$value2\"", $_SQL_TypeInvs{ $datatype } |
|
278 | + ); |
|
279 | + } |
|
280 | + $self->bind_param( $i, $value2 , { TYPE => $datatype } ) |
|
281 | + or croak( "$DBI::errstr\n" ); |
|
282 | + } |
|
283 | + return $self; |
|
284 | +} |
|
285 | + |
|
286 | +1; |
|
287 | + |
|
288 | +# EOF |
|
289 | +``` |
|
290 | + |
|
291 | +### testNamedParams_MySQL.pl |
|
292 | +```perl |
|
293 | +#!/usr/bin/perl |
|
294 | +# DBIx::NamedParams のテスト |
|
295 | + |
|
296 | +use strict; |
|
297 | +use warnings; |
|
298 | +use utf8; |
|
299 | +use Encode; |
|
300 | +use YAML::Syck; |
|
301 | +use POSIX qw( strftime ); |
|
302 | +use FindBin::libs; |
|
303 | +use lib qw( /home/Shared/lib ); |
|
304 | +use DBIx::NamedParams; |
|
305 | + |
|
306 | +( $ENV{'LANG'} || '' ) =~ /\.(.*)$/; # ja_JP.UTF-8 |
|
307 | +my $charsetConsole = $1 || 'CP932'; |
|
308 | +my $charsetFile = 'UTF-8'; |
|
309 | + |
|
310 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
311 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
312 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
313 | + |
|
314 | +$YAML::Syck::ImplicitUnicode = 1; |
|
315 | + |
|
316 | +my $path = $FindBin::RealBin . '/'; |
|
317 | +my $yaml = $path . 'DB_Connect_MySQL.yml'; |
|
318 | +my $input = $path . 'InputData.yml'; |
|
319 | + |
|
320 | +my $DB_Info = YAML::Syck::LoadFile( $yaml ) or die( "$yaml: $!\n" ); |
|
321 | +foreach( keys( %{$DB_Info} ) ){ |
|
322 | + $DB_Info->{'DSN'} =~ s/_${_}_/$DB_Info->{$_}/; |
|
323 | +} |
|
324 | + |
|
325 | +my $dbh = DBI->connect( |
|
326 | + 'DBI:' . $DB_Info->{'DSN'}, |
|
327 | + $DB_Info->{'User'}, |
|
328 | + $DB_Info->{'Password'}, |
|
329 | + $DB_Info->{'Options'} |
|
330 | +) or die( "$DBI::errstr\n" ); |
|
331 | + |
|
332 | +#DBIx::NamedParams::debug_log( 'testNamedParams.log' ); |
|
333 | + |
|
334 | +#my %DrvTypeToSQLType = $dbh->driver_typename_map(); |
|
335 | +#print Dump( \%DrvTypeToSQLType ); |
|
336 | + |
|
337 | +my $sql_insert = qq{ |
|
338 | + INSERT INTO |
|
339 | + `Users` |
|
340 | + ( `Name`, `Status`, `RegDate` ) |
|
341 | + VALUES |
|
342 | + ( :Name-VARCHAR, :State-INTEGER, :Now-DATETIME ); |
|
343 | +}; |
|
344 | + |
|
345 | +my $sth_insert = $dbh->prepare_ex( $sql_insert ) or die( "$DBI::errstr\n" ); |
|
346 | + |
|
347 | +my $users = YAML::Syck::LoadFile( $input ) or die( "$input: $!\n" ); |
|
348 | +#print Dump( $users ); |
|
349 | +#exit; |
|
350 | + |
|
351 | +foreach( @{$users} ){ |
|
352 | + $_->{'Now'} = strftime( "%Y-%m-%d %H:%M:%S", localtime ); |
|
353 | + print Dump( $_ ); |
|
354 | + $sth_insert->bind_param_ex( $_ ); |
|
355 | + $sth_insert->execute() or die( "$DBI::errstr\n" ); |
|
356 | + sleep( 1 ); |
|
357 | +} |
|
358 | +$sth_insert->finish; |
|
359 | + |
|
360 | +my $sql_select = qq{ |
|
361 | + SELECT |
|
362 | + `ID`, `Name`, `Status`, `RegDate` |
|
363 | + FROM |
|
364 | + `Users` |
|
365 | + WHERE |
|
366 | + `Status` in ( :State+-INTEGER ); |
|
367 | +}; |
|
368 | + |
|
369 | +my $sth_select = $dbh->prepare_ex( $sql_select, { 'State' => [ 1,2,5 ] } ) |
|
370 | + or die( "$DBI::errstr\n" ); |
|
371 | +$sth_select->execute() or die( "$DBI::errstr\n" ); |
|
372 | +do { |
|
373 | + no warnings 'uninitialized'; |
|
374 | + while( my @a = $sth_select->fetchrow_array ){ |
|
375 | + printf( "%s\n", join( "\t", @a ) ); |
|
376 | + } |
|
377 | +}while( $sth_select->{odbc_more_results} ); |
|
378 | +$sth_select->finish; |
|
379 | + |
|
380 | +$dbh->disconnect; |
|
381 | + |
|
382 | +exit; |
|
383 | + |
|
384 | +# EOF |
|
385 | +``` |
|
386 | + |
|
387 | +### DB_Connect_MySQL.yml |
|
388 | +``` |
|
389 | +# DB接続情報 |
|
390 | +Driver: mysql |
|
391 | +Server: localhost |
|
392 | +Port: 3306 |
|
393 | +User: TestUser |
|
394 | +Password: "Test" # 記号を含む場合は""で括る |
|
395 | +DB: TestDB |
|
396 | +Options: |
|
397 | + mysql_enable_utf8: 1 |
|
398 | +DSN: "_Driver_:database=_DB_; host=_Server_; port=_Port_;" # Linux |
|
399 | +#DSN: "_Driver_:database=_DB_:host=_Server_" # Windows |
|
400 | +``` |
|
401 | + |
|
402 | +### createUsers_MySQL.sql |
|
403 | +```sql |
|
404 | +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; |
|
405 | + |
|
406 | +CREATE TABLE `Users` ( |
|
407 | + `ID` int(11) NOT NULL AUTO_INCREMENT, |
|
408 | + `Name` varchar(40) NOT NULL, |
|
409 | + `Status` int(11) NOT NULL DEFAULT '0', |
|
410 | + `RegDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
|
411 | + PRIMARY KEY (`ID`) |
|
412 | +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; |
|
413 | +``` |
|
414 | + |
|
415 | +### InputData.yml (MySQL/MSSQL 共通) |
|
416 | +``` |
|
417 | +--- |
|
418 | +- { Name: リオ, State: 1 } |
|
419 | +- { Name: ミント, State: 2 } |
|
420 | +- { Name: ローザ, State: 3 } |
|
421 | +- { Name: リンダ, State: 4 } |
|
422 | +- { Name: リナ, State: 5 } |
|
423 | +- { Name: アーニャ, State: 6 } |
|
424 | +``` |
|
425 | + |
|
426 | +### testNamedParams_MSSQL.pl |
|
427 | +```perl |
|
428 | +#!/usr/bin/perl |
|
429 | +# DBIx::NamedParams のテスト |
|
430 | + |
|
431 | +use strict; |
|
432 | +use warnings; |
|
433 | +use utf8; |
|
434 | +use Encode; |
|
435 | +use YAML::Syck; |
|
436 | +use POSIX qw( strftime ); |
|
437 | +use FindBin::libs; |
|
438 | +use lib qw( /home/Shared/lib ); |
|
439 | +use DBIx::NamedParams; |
|
440 | + |
|
441 | +( $ENV{'LANG'} || '' ) =~ /\.(.*)$/; # ja_JP.UTF-8 |
|
442 | +my $charsetConsole = $1 || 'CP932'; |
|
443 | +my $charsetFile = 'UTF-8'; |
|
444 | + |
|
445 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
446 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
447 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
448 | + |
|
449 | +$YAML::Syck::ImplicitUnicode = 1; |
|
450 | + |
|
451 | +my $path = $FindBin::RealBin . '/'; |
|
452 | +my $yaml = $path . 'DB_Connect_MSSQL.yml'; |
|
453 | +my $input = $path . 'InputData.yml'; |
|
454 | + |
|
455 | +my $DB_Info = YAML::Syck::LoadFile( $yaml ) or die( "$yaml: $!\n" ); |
|
456 | +foreach( keys( %{$DB_Info} ) ){ |
|
457 | + $DB_Info->{'DSN'} =~ s/_${_}_/$DB_Info->{$_}/; |
|
458 | +} |
|
459 | + |
|
460 | +my $dbh = DBI->connect( |
|
461 | + 'DBI:' . $DB_Info->{'DSN'}, |
|
462 | + $DB_Info->{'User'}, |
|
463 | + $DB_Info->{'Password'}, |
|
464 | + $DB_Info->{'Options'} |
|
465 | +) or die( "$DBI::errstr\n" ); |
|
466 | + |
|
467 | +#DBIx::NamedParams::debug_log( 'testNamedParams.log' ); |
|
468 | + |
|
469 | +#my %DrvTypeToSQLType = $dbh->driver_typename_map(); |
|
470 | +#print Dump( \%DrvTypeToSQLType ); |
|
471 | + |
|
472 | +my $sql_insert = qq{ |
|
473 | + INSERT INTO |
|
474 | + [Users] |
|
475 | + ( [Name], [Status], [RegDate] ) |
|
476 | + VALUES |
|
477 | + ( :Name-WVARCHAR, :State-INTEGER, :Now-WVARCHAR ); |
|
478 | +}; |
|
479 | + |
|
480 | +my $sth_insert = $dbh->prepare_ex( $sql_insert ) or die( "$DBI::errstr\n" ); |
|
481 | + |
|
482 | +my $users = YAML::Syck::LoadFile( $input ) or die( "$input: $!\n" ); |
|
483 | +#print Dump( $users ); |
|
484 | +#exit; |
|
485 | + |
|
486 | +foreach( @{$users} ){ |
|
487 | + $_->{'Now'} = strftime( "%Y-%m-%d %H:%M:%S", localtime ); |
|
488 | + print Dump( $_ ); |
|
489 | + $sth_insert->bind_param_ex( $_ ); |
|
490 | + $sth_insert->execute() or die( "$DBI::errstr\n" ); |
|
491 | + sleep( 1 ); |
|
492 | +} |
|
493 | +$sth_insert->finish; |
|
494 | + |
|
495 | +my $sql_select = qq{ |
|
496 | + SELECT |
|
497 | + [ID], [Name], [Status], [RegDate] |
|
498 | + FROM |
|
499 | + [Users] |
|
500 | + WHERE |
|
501 | + [Status] in ( :State+-INTEGER ); |
|
502 | +}; |
|
503 | + |
|
504 | +my $sth_select = $dbh->prepare_ex( $sql_select, { 'State' => [ 1,2,5 ] } ) |
|
505 | + or die( "$DBI::errstr\n" ); |
|
506 | +$sth_select->execute() or die( "$DBI::errstr\n" ); |
|
507 | +do { |
|
508 | + no warnings 'uninitialized'; |
|
509 | + while( my @a = $sth_select->fetchrow_array ){ |
|
510 | + printf( "%s\n", join( "\t", @a ) ); |
|
511 | + } |
|
512 | +}while( $sth_select->{odbc_more_results} ); |
|
513 | +$sth_select->finish; |
|
514 | + |
|
515 | +$dbh->disconnect; |
|
516 | + |
|
517 | +exit; |
|
518 | + |
|
519 | +# EOF |
|
520 | +``` |
|
521 | + |
|
522 | +### DB_Connect_MSSQL.yml |
|
523 | +``` |
|
524 | +# DB接続情報 |
|
525 | +Driver: ODBC |
|
526 | +Server: localhost\SQLExress,1433 # <サーバ名>\<インスタンス名>[,<ポート>] |
|
527 | +User: TestUser |
|
528 | +Password: "Test" # 記号を含む場合は""で括る |
|
529 | +DB: TestDB |
|
530 | +Options: |
|
531 | + LongTruncOk: 1 |
|
532 | + LongReadLen: 8192 |
|
533 | +DSN: _Driver_:Driver={SQL Server}; Server={_Server_}; Database=_DB_; |
|
534 | +``` |
|
535 | + |
|
536 | +### createUsers_MSSQL.sql |
|
537 | +```sql |
|
538 | +USE [TestDB] |
|
539 | +GO |
|
540 | + |
|
541 | +SET ANSI_NULLS ON |
|
542 | +GO |
|
543 | + |
|
544 | +SET QUOTED_IDENTIFIER ON |
|
545 | +GO |
|
546 | + |
|
547 | +CREATE TABLE [dbo].[Users]( |
|
548 | + [ID] [int] IDENTITY(1,1) NOT NULL, |
|
549 | + [Name] [nvarchar](40) NOT NULL, |
|
550 | + [Status] [int] NOT NULL, |
|
551 | + [RegDate] [datetime] NULL, |
|
552 | + CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED |
|
553 | + ( |
|
554 | + [ID] ASC |
|
555 | + ) WITH ( |
|
556 | + PAD_INDEX = OFF, |
|
557 | + STATISTICS_NORECOMPUTE = OFF, |
|
558 | + IGNORE_DUP_KEY = OFF, |
|
559 | + ALLOW_ROW_LOCKS = ON, |
|
560 | + ALLOW_PAGE_LOCKS = ON |
|
561 | + ) ON [PRIMARY] |
|
562 | +) ON [PRIMARY] |
|
563 | +GO |
|
564 | + |
|
565 | +ALTER TABLE [dbo].[Users] |
|
566 | +ADD CONSTRAINT [DF_Users_RegDate] |
|
567 | +DEFAULT (getdate()) FOR [RegDate] |
|
568 | +GO |
|
569 | +``` |
|
570 | + |
|
571 | +## SQLTypes |
|
572 | +### getSQLTypes.pl |
|
573 | +```perl |
|
574 | +# SQLタイプ一覧 |
|
575 | + |
|
576 | +use strict; |
|
577 | +use warnings; |
|
578 | +use utf8; |
|
579 | +use Encode; |
|
580 | +use POSIX qw( strftime ); |
|
581 | +use FindBin::libs; |
|
582 | +use lib qw( /home/Shared/lib ); |
|
583 | +use DBIx::NamedParams; |
|
584 | + |
|
585 | +print "Perl version: " . $] . "\n"; |
|
586 | +print "DBI version: " . $DBI::VERSION . "\n"; |
|
587 | +print strftime( "%Y-%m-%d %H:%M:%S\n\n", localtime ); |
|
588 | +print join( "\n", DBIx::NamedParams::all_sql_types() ) . "\n"; |
|
589 | + |
|
590 | +# EOF |
|
591 | +``` |
|
592 | + |
|
593 | +### 出力 |
|
594 | +``` |
|
595 | +Perl version: 5.010001 |
|
596 | +DBI version: 1.616 |
|
597 | +2011-06-17 00:37:32 |
|
598 | + |
|
599 | +ALL_TYPES |
|
600 | +ARRAY |
|
601 | +ARRAY_LOCATOR |
|
602 | +BIGINT |
|
603 | +BINARY |
|
604 | +BIT |
|
605 | +BLOB |
|
606 | +BLOB_LOCATOR |
|
607 | +BOOLEAN |
|
608 | +CHAR |
|
609 | +CLOB |
|
610 | +CLOB_LOCATOR |
|
611 | +DATE |
|
612 | +DATETIME |
|
613 | +DECIMAL |
|
614 | +DOUBLE |
|
615 | +FLOAT |
|
616 | +GUID |
|
617 | +INTEGER |
|
618 | +INTERVAL |
|
619 | +INTERVAL_DAY |
|
620 | +INTERVAL_DAY_TO_HOUR |
|
621 | +INTERVAL_DAY_TO_MINUTE |
|
622 | +INTERVAL_DAY_TO_SECOND |
|
623 | +INTERVAL_HOUR |
|
624 | +INTERVAL_HOUR_TO_MINUTE |
|
625 | +INTERVAL_HOUR_TO_SECOND |
|
626 | +INTERVAL_MINUTE |
|
627 | +INTERVAL_MINUTE_TO_SECOND |
|
628 | +INTERVAL_MONTH |
|
629 | +INTERVAL_SECOND |
|
630 | +INTERVAL_YEAR |
|
631 | +INTERVAL_YEAR_TO_MONTH |
|
632 | +LONGVARBINARY |
|
633 | +LONGVARCHAR |
|
634 | +MULTISET |
|
635 | +MULTISET_LOCATOR |
|
636 | +NUMERIC |
|
637 | +REAL |
|
638 | +REF |
|
639 | +ROW |
|
640 | +SMALLINT |
|
641 | +TIME |
|
642 | +TIMESTAMP |
|
643 | +TINYINT |
|
644 | +TYPE_DATE |
|
645 | +TYPE_TIME |
|
646 | +TYPE_TIMESTAMP |
|
647 | +TYPE_TIMESTAMP_WITH_TIMEZONE |
|
648 | +TYPE_TIME_WITH_TIMEZONE |
|
649 | +UDT |
|
650 | +UDT_LOCATOR |
|
651 | +UNKNOWN_TYPE |
|
652 | +VARBINARY |
|
653 | +VARCHAR |
|
654 | +WCHAR |
|
655 | +WLONGVARCHAR |
|
656 | +WVARCHAR |
|
657 | +``` |
|
658 | + |
|
659 | +## MySQLのデータタイプ |
|
660 | +``` |
|
661 | +--- |
|
662 | +bigint: BIGINT |
|
663 | +bigint auto_increment: BIGINT |
|
664 | +bigint unsigned: BIGINT |
|
665 | +bigint unsigned auto_increment: BIGINT |
|
666 | +bit: BIT |
|
667 | +bit auto_increment: BIT |
|
668 | +blob: LONGVARBINARY |
|
669 | +char: CHAR |
|
670 | +date: DATE |
|
671 | +datetime: TIMESTAMP |
|
672 | +decimal: NUMERIC |
|
673 | +double: DOUBLE |
|
674 | +double auto_increment: DOUBLE |
|
675 | +enum: ALL_TYPES |
|
676 | +float: FLOAT |
|
677 | +float auto_increment: FLOAT |
|
678 | +int: INTEGER |
|
679 | +int auto_increment: INTEGER |
|
680 | +int unsigned: INTEGER |
|
681 | +int unsigned auto_increment: INTEGER |
|
682 | +integer: INTEGER |
|
683 | +integer auto_increment: INTEGER |
|
684 | +integer unsigned: INTEGER |
|
685 | +integer unsigned auto_increment: INTEGER |
|
686 | +long varbinary: LONGVARBINARY |
|
687 | +long varchar: LONGVARCHAR |
|
688 | +longblob: LONGVARBINARY |
|
689 | +mediumblob: LONGVARBINARY |
|
690 | +mediumint: INTEGER |
|
691 | +mediumint auto_increment: INTEGER |
|
692 | +mediumint unsigned: INTEGER |
|
693 | +mediumint unsigned auto_increment: INTEGER |
|
694 | +mediumtext: LONGVARCHAR |
|
695 | +numeric: NUMERIC |
|
696 | +set: ALL_TYPES |
|
697 | +smallint: SMALLINT |
|
698 | +smallint auto_increment: SMALLINT |
|
699 | +smallint unsigned: SMALLINT |
|
700 | +smallint unsigned auto_increment: SMALLINT |
|
701 | +text: LONGVARCHAR |
|
702 | +time: TIME |
|
703 | +timestamp: TIMESTAMP |
|
704 | +tinyblob: VARBINARY |
|
705 | +tinyint: TINYINT |
|
706 | +tinyint auto_increment: TINYINT |
|
707 | +tinyint unsigned: TINYINT |
|
708 | +tinyint unsigned auto_increment: TINYINT |
|
709 | +varchar: VARCHAR |
|
710 | +year: SMALLINT |
|
711 | +``` |
|
712 | + |
|
713 | +## MS SQL Server のデータタイプ |
|
714 | +``` |
|
715 | +--- |
|
716 | +bigint: BIGINT |
|
717 | +bigint identity: BIGINT |
|
718 | +binary: BINARY |
|
719 | +bit: BIT |
|
720 | +char: CHAR |
|
721 | +date: WVARCHAR |
|
722 | +datetime: WVARCHAR |
|
723 | +datetime2: WVARCHAR |
|
724 | +datetimeoffset: WVARCHAR |
|
725 | +decimal: DECIMAL |
|
726 | +decimal() identity: DECIMAL |
|
727 | +float: FLOAT |
|
728 | +image: LONGVARBINARY |
|
729 | +int: INTEGER |
|
730 | +int identity: INTEGER |
|
731 | +money: DECIMAL |
|
732 | +nchar: WCHAR |
|
733 | +ntext: WLONGVARCHAR |
|
734 | +numeric: NUMERIC |
|
735 | +numeric() identity: NUMERIC |
|
736 | +nvarchar: WVARCHAR |
|
737 | +real: REAL |
|
738 | +smalldatetime: WVARCHAR |
|
739 | +smallint: SMALLINT |
|
740 | +smallint identity: SMALLINT |
|
741 | +smallmoney: DECIMAL |
|
742 | +sql_variant: WVARCHAR |
|
743 | +sysname: WVARCHAR |
|
744 | +text: LONGVARCHAR |
|
745 | +time: WVARCHAR |
|
746 | +timestamp: BINARY |
|
747 | +tinyint: TINYINT |
|
748 | +tinyint identity: TINYINT |
|
749 | +uniqueidentifier: GUID |
|
750 | +varbinary: VARBINARY |
|
751 | +varchar: VARCHAR |
|
752 | +xml: WLONGVARCHAR |
|
753 | +``` |
|
754 | + |
|
755 | +## リンク |
|
756 | +- [[DBIx::Custom|Perl/DBIx-Custom]] |
|
757 | + |
|
758 | +- [安全なウェブサイトの作り方](http://www.ipa.go.jp/security/vuln/websecurity.html) 安全なSQLの呼び出し方 |
|
759 | + |
|
760 | +- http://perldoc.jp/ |
|
761 | + - [perlobj - Perl のオブジェクト](http://perldoc.jp/docs/perl/5.10.0/perlobj.pod) |
|
762 | + - [perlmod - Perl のモジュール (パッケージとシンボルテーブル)](http://perldoc.jp/docs/perl/5.10.0/perlmod.pod) |
|
763 | + |
|
764 | +- [ダウンロードたけし(寅年)の日記](http://d.hatena.ne.jp/download_takeshi/) |
|
765 | + - [DBIでbindした後のSQL文を引っ張り出す方法](http://d.hatena.ne.jp/download_takeshi/20081209/1228837813) |
|
766 | + - [DBI/Executed.pm](http://coderepos.org/share/browser/lang/perl/DBI-Executed/trunk/lib/DBI/Executed.pm) |
|
767 | + |
|
768 | +- [ブログが続かないわけ](http://en.yummy.stripper.jp/) |
|
769 | + - [[Perl][微エロ注意]画像収集のときにいつも同じイディオムを書いているのをやめたい](http://en.yummy.stripper.jp/?eid=1159981) |
|
770 | + |
|
771 | +- [404 Blog Not Found](http://blog.livedoor.jp/dankogai/) |
|
772 | + - [perl - use Carp; # warn() と die() だけじゃなくて](http://blog.livedoor.jp/dankogai/archives/51073468.html) |
|
773 | + - [perl - no warnings 'unintialized'](http://blog.livedoor.jp/dankogai/archives/50622749.html) |
|
774 | + - [perl - デフォルト値のperlらしい指定法](http://blog.livedoor.jp/dankogai/archives/51074877.html) |
|
775 | + - [perl - 継承を使いたいワケ](http://blog.livedoor.jp/dankogai/archives/50706327.html) |
|
776 | + |
|
777 | +- [サンプルコードによるPerl入門](http://d.hatena.ne.jp/perlcodesample/) |
|
778 | + - [Exporter - 関数のエクスポート / Perlモジュール徹底解説](http://d.hatena.ne.jp/perlcodesample/20100426/1270894115) |
|
779 | + - [柔軟なSQL / DBIx::Customの特徴](http://d.hatena.ne.jp/perlcodesample/20110118/1300165343) |
|
780 | + - [DBIx::Connectorを利用する / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110123/1300165343) |
|
781 | + - [DBIx::Connectorによるトランザクション処理 / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110125/1300165343) |
|
782 | + - [行の挿入 insert / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110129/1300165343) |
|
783 | + - [行の更新 update / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110130/1300165343) |
|
784 | + - [DBIx::Customの紹介(1) - モデル](http://d.hatena.ne.jp/perlcodesample/20110131/1300165343) |
|
785 | + - [すべての行の更新 update_all / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110201/1300165343) |
|
786 | + - [行の削除 delete / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110202/1300165343) |
|
787 | + - [すべての行の削除 delete_all / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110203/1300165343) |
|
788 | + - [Where句で日付の範囲を指定する / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110204/1300165343) |
|
789 | + - [予約語を使用している列やテーブルに対応する / DBIx::Custom Tips](http://d.hatena.ne.jp/perlcodesample/20110207/1300165343) |
|
790 | + - [DBIx::Customの特徴(2) SQLの知識がそのまま利用できる](http://d.hatena.ne.jp/perlcodesample/20110208/1300165343) |
|
791 | + |
|
792 | +- [Islands in the byte stream](http://d.hatena.ne.jp/gfx/) |
|
793 | + - [Don't use base.pm, use parent.pm instead!](http://d.hatena.ne.jp/gfx/20101226/1293342019) |
|
794 | + |
|
795 | +- [Perl-users.jp](http://perl-users.jp/) |
|
796 | + - [Perl 5 今昔](http://perl-users.jp/nowpast.html) |
|
797 | + - [使っちゃいけない標準モジュール - JPerl advent calendar 2010 casual Track](http://perl-users.jp/articles/advent-calendar/2010/casual/23) |
|
798 | + |
|
799 | +- [Part1 正しいPerl/CGIの書き方 - Webプログラミング実力アップ:ITpro](http://itpro.nikkeibp.co.jp/article/COLUMN/20071011/284280/) Module::Starter::PBP によるモジュール開発例 |
|
800 | + |
|
801 | +- [楽:技林ブログ](http://tech.bayashi.jp/) |
|
802 | + - [はじめてのPerlモジュール開発メモ/楽](http://tech.bayashi.jp/archives/entry/perl/2008/002326.html) |
|
803 | + |
|
804 | +- [個人的なメモのページ](http://www12.atpages.jp/~lottz/pukiwikiplus/) |
|
805 | + - [Perl_Modules](http://www12.atpages.jp/~lottz/pukiwikiplus/index.php?Perl_Modules) |
|
806 | + |
|
807 | +- [CPAN:DBI](http://search.cpan.org/dist/DBI) |
|
808 | +- [CPAN:DBD-mysql](http://search.cpan.org/dist/DBD-mysql) |
|
809 | +- [CPAN:DBD-ODBC](http://search.cpan.org/dist/DBD-ODBC) |
|
810 | + |
|
811 | +- [CPAN:DBIx-Custom](http://search.cpan.org/dist/DBIx-Custom) |
|
812 | + - [CPAN:DBIx-Custom/lib/DBIx/Custom/Guide/Ja.pod](http://search.cpan.org/dist/DBIx-Custom/lib/DBIx/Custom/Guide/Ja.pod) |
|
813 | + - [DBIx::Custom Wiki - GitHub](https://github.com/yuki-kimoto/DBIx-Custom/wiki) |
|
814 | +- [CPAN:DBIx-NamedBinding](http://search.cpan.org/dist/DBIx-NamedBinding) |
|
815 | +- [CPAN:DBIx-Simple](http://search.cpan.org/dist/DBIx-Simple) |
|
816 | +- [CPAN:DBIx-InsertHash](http://search.cpan.org/dist/DBIx-InsertHash) |
|
817 | + |
|
818 | +- [CPAN:perl/lib/Carp.pm](http://search.cpan.org/dist/perl/lib/Carp.pm) |
|
819 | +- [CPAN:parent](http://search.cpan.org/dist/parent) |
|
820 | +- [CPAN:base](http://search.cpan.org/dist/base) |
|
821 | +- [CPAN:Log-Dispatch](http://search.cpan.org/dist/Log-Dispatch) |
|
822 | + |
|
823 | +- [CPAN:perl](http://search.cpan.org/dist/perl) POSIX strftime |
|
824 | + |
|
825 | +- [CPAN:FindBin-libs](http://search.cpan.org/dist/FindBin-libs) |
|
... | ... | \ No newline at end of file |
Perl/EPS\343\203\225\343\202\241\343\202\244\343\203\253\344\275\234\346\210\220/Home.md
... | ... | @@ -0,0 +1,24 @@ |
1 | +# EPSファイル作成 |
|
2 | +[[_TOC_]] |
|
3 | +~~#ls2~~ |
|
4 | +---- |
|
5 | +## 幾何学図形と文字 |
|
6 | +### 概要 |
|
7 | +- 使用しているフォントは「小塚明朝 Std - M」。 |
|
8 | +- EPS中で「Shift_JIS」で指定する場合は「KozMinStd-Medium-90ms-RKSJ-H」と記述する。(横書き) |
|
9 | +- 画像の埋め込みは行っていない。 |
|
10 | + |
|
11 | +### ダウンロード |
|
12 | +- ソースコードと出力されるEPSファイル<br /> |
|
13 | +[createEPS.zip](createEPS.zip) |
|
14 | +- EPSファイルをAcrobat Distiller 6でPDFに変換したもの<br /> |
|
15 | +[ToneChart.pdf](ToneChart.pdf) |
|
16 | + |
|
17 | +## リンク |
|
18 | +- [[Typography_PDF|etc/Typography_PDF]] |
|
19 | +- [[文字コード|Perl/文字コード]] |
|
20 | + |
|
21 | +- [CPAN:PostScript-Simple](http://search.cpan.org/dist/PostScript-Simple) |
|
22 | +- [CPAN:Font-TTF](http://search.cpan.org/dist/Font-TTF) / [Manual](http://search.cpan.org/dist/Font-TTF/lib/Font/TTF/Manual.pod) |
|
23 | + |
|
24 | +- [中島 靖](http://hp1.jonex.ne.jp/~nakajima.yasushi/) / [PDFJ - 日本語PDF生成モジュール](http://hp1.jonex.ne.jp/~nakajima.yasushi/PDFJ.jp.html) |
|
... | ... | \ No newline at end of file |
Perl/EPS\343\203\225\343\202\241\343\202\244\343\203\253\344\275\234\346\210\220/SimpleEPS.md
... | ... | @@ -0,0 +1,41 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# 概要 |
|
4 | +- 単純なEPSの例。 |
|
5 | +- ドキュメントサイズ: 200 x 200pt (70.6 x 70.6 mm) |
|
6 | +- 背景: M20% |
|
7 | +- 文字: 小塚明朝Pro Regular, 36pt |
|
8 | +- 文字コード: UTF-8, BOM無し (BOMを付けるとDistillerでエラーとなる) |
|
9 | +- 改行コード: CRLF |
|
10 | + |
|
11 | +# ソース |
|
12 | +- [Simple.zip](Simple.zip) |
|
13 | +``` |
|
14 | +%!PS-Adobe-3.0 EPSF-3.0 |
|
15 | +%%BoundingBox: 0 0 200 200 |
|
16 | +%%EndComments |
|
17 | + |
|
18 | +%%BeginProlog |
|
19 | +%%EndProlog |
|
20 | + |
|
21 | +%%Page: 1 1 |
|
22 | + |
|
23 | +% Frame |
|
24 | +0 0 moveto |
|
25 | +0 200 lineto |
|
26 | +200 200 lineto |
|
27 | +200 0 lineto |
|
28 | +0 0.2 0 0 setcmykcolor |
|
29 | +fill |
|
30 | + |
|
31 | +% Font |
|
32 | +/KozMinPro-Regular-UniJIS-UTF8-H findfont 18 scalefont setfont |
|
33 | +0 0 0 1 setcmykcolor |
|
34 | + |
|
35 | +% String |
|
36 | +27 90 moveto |
|
37 | +(ポストスクリプト) show |
|
38 | + |
|
39 | +showpage |
|
40 | + |
|
41 | +% EOF |
|
... | ... | \ No newline at end of file |
Perl/EPS\343\203\225\343\202\241\343\202\244\343\203\253\344\275\234\346\210\220/V\345\234\247\347\235\200\350\221\211\346\233\270\343\203\206\343\203\263\343\203\227\343\203\254\343\203\274\343\203\210.md
... | ... | @@ -0,0 +1,225 @@ |
1 | +~~#navi(Perl/EPSファイル作成)~~ |
|
2 | +[[_TOC_]] |
|
3 | +# V圧着葉書テンプレート |
|
4 | +## 概要 |
|
5 | +- V圧着葉書をデザインする際のテンプレート。 |
|
6 | +- Perl使っていない素のEPSファイルだけど、関連ってことで。 |
|
7 | + |
|
8 | +## 中面 |
|
9 | +``` |
|
10 | +%!PS-Adobe-3.0 EPSF-3.0 |
|
11 | +%%BoundingBox: 0 0 841.89 595.28 |
|
12 | + |
|
13 | +% V圧着葉書テンプレート (中面) |
|
14 | + |
|
15 | +% mm -> point 換算係数 |
|
16 | +/mm2point 72 25.4 div def |
|
17 | + |
|
18 | +/width 297 mm2point mul def |
|
19 | +/height 210 mm2point mul def |
|
20 | + |
|
21 | +/x0 297 mm2point mul def |
|
22 | +/y0 210 mm2point mul def |
|
23 | + |
|
24 | +/x1 27 mm2point mul def |
|
25 | +/x2 47 mm2point mul def |
|
26 | +/x3 50 mm2point mul def |
|
27 | +/x4 56 mm2point mul def |
|
28 | +/x5 150 mm2point mul def |
|
29 | +/x6 245 mm2point mul def |
|
30 | +/x7 248 mm2point mul def |
|
31 | +/x8 268 mm2point mul def |
|
32 | + |
|
33 | +/y1 7 mm2point mul neg y0 add def |
|
34 | +/y2 27 mm2point mul neg y0 add def |
|
35 | +/y3 30 mm2point mul neg y0 add def |
|
36 | +/y4 175 mm2point mul neg y0 add def |
|
37 | +/y5 178 mm2point mul neg y0 add def |
|
38 | +/y6 198 mm2point mul neg y0 add def |
|
39 | + |
|
40 | +/tx 55 mm2point mul def |
|
41 | +/ty 20 mm2point mul neg y0 add def |
|
42 | + |
|
43 | +0.3 setlinewidth |
|
44 | + |
|
45 | +% 全体枠 |
|
46 | +0 0 moveto |
|
47 | +0 height lineto |
|
48 | +width height lineto |
|
49 | +width 0 lineto |
|
50 | +closepath |
|
51 | +0 0 0 1 setcmykcolor |
|
52 | +stroke |
|
53 | + |
|
54 | +%タイトル |
|
55 | +/KozGoPro-Medium-UniJIS-UTF8-H findfont 14 scalefont setfont |
|
56 | +tx ty moveto |
|
57 | +0 0 0 1 setcmykcolor |
|
58 | +(V圧着葉書テンプレート (中面)) show |
|
59 | + |
|
60 | +% 断ち落とし込みの領域 |
|
61 | +x2 y2 moveto x7 y2 lineto x7 y5 lineto x2 y5 lineto |
|
62 | +closepath |
|
63 | +1 0 0 0 setcmykcolor |
|
64 | +stroke |
|
65 | + |
|
66 | +% 断裁後の領域 |
|
67 | +x3 y3 moveto x6 y3 lineto x6 y4 lineto x3 y4 lineto |
|
68 | +closepath |
|
69 | +1 0 0 0 setcmykcolor |
|
70 | +stroke |
|
71 | + |
|
72 | +% トンボ |
|
73 | +x2 y1 moveto x2 y3 lineto x1 y3 lineto |
|
74 | +x3 y1 moveto x3 y2 lineto x1 y2 lineto |
|
75 | +x6 y1 moveto x6 y2 lineto x8 y2 lineto |
|
76 | +x7 y1 moveto x7 y3 lineto x8 y3 lineto |
|
77 | +x1 y4 moveto x2 y4 lineto x2 y6 lineto |
|
78 | +x1 y5 moveto x3 y5 lineto x3 y6 lineto |
|
79 | +x6 y6 moveto x6 y5 lineto x8 y5 lineto |
|
80 | +x7 y6 moveto x7 y4 lineto x8 y4 lineto |
|
81 | +x5 y1 moveto x5 y2 lineto |
|
82 | +x5 y5 moveto x5 y6 lineto |
|
83 | +0 0 0 1 setcmykcolor |
|
84 | +stroke |
|
85 | + |
|
86 | +% 剥がししろ |
|
87 | +x2 y2 moveto x4 y2 lineto x4 y5 lineto x2 y5 lineto |
|
88 | +1 0.8 0 0 setcmykcolor |
|
89 | +fill |
|
90 | + |
|
91 | +showpage |
|
92 | + |
|
93 | +% EOF |
|
94 | +``` |
|
95 | + |
|
96 | +## 宛名面 |
|
97 | +``` |
|
98 | +%!PS-Adobe-3.0 EPSF-3.0 |
|
99 | +%%BoundingBox: 0 0 841.89 595.28 |
|
100 | + |
|
101 | +% V圧着葉書テンプレート (宛名面) |
|
102 | + |
|
103 | +% mm -> point 換算係数 |
|
104 | +/mm2point 72 25.4 div def |
|
105 | + |
|
106 | +/width 297 mm2point mul def |
|
107 | +/height 210 mm2point mul def |
|
108 | + |
|
109 | +/x0 297 mm2point mul def |
|
110 | +/y0 210 mm2point mul def |
|
111 | + |
|
112 | +/x1 27 mm2point mul neg x0 add def |
|
113 | +/x2 47 mm2point mul neg x0 add def |
|
114 | +/x3 50 mm2point mul neg x0 add def |
|
115 | +/x4 150 mm2point mul neg x0 add def |
|
116 | +/x5 245 mm2point mul neg x0 add def |
|
117 | +/x6 248 mm2point mul neg x0 add def |
|
118 | +/x7 268 mm2point mul neg x0 add def |
|
119 | + |
|
120 | +/y1 7 mm2point mul neg y0 add def |
|
121 | +/y2 27 mm2point mul neg y0 add def |
|
122 | +/y3 30 mm2point mul neg y0 add def |
|
123 | +/y4 175 mm2point mul neg y0 add def |
|
124 | +/y5 178 mm2point mul neg y0 add def |
|
125 | +/y6 198 mm2point mul neg y0 add def |
|
126 | + |
|
127 | +/tx 55 mm2point mul def |
|
128 | +/ty 20 mm2point mul neg y0 add def |
|
129 | + |
|
130 | +/bx1 48.1 8 add mm2point mul neg x4 add def |
|
131 | +/bx2 7.0 mm2point mul bx1 add def |
|
132 | +/bx3 14.0 mm2point mul bx1 add def |
|
133 | +/bx4 21.7 mm2point mul bx1 add def |
|
134 | +/bx5 28.5 mm2point mul bx1 add def |
|
135 | +/bx6 35.3 mm2point mul bx1 add def |
|
136 | +/bx7 42.1 mm2point mul bx1 add def |
|
137 | +/bx8 20.2 mm2point mul bx1 add def |
|
138 | +/by1 11.8 mm2point mul neg y3 add def |
|
139 | +/by2 15.8 mm2point mul neg y3 add def |
|
140 | + |
|
141 | +/bw 6.1 mm2point mul def |
|
142 | +/bh 8.4 mm2point mul neg def |
|
143 | + |
|
144 | +/drawBox { |
|
145 | + 2 dict begin |
|
146 | + /yy exch def |
|
147 | + /xx exch def |
|
148 | + xx yy moveto |
|
149 | + bw 0 rlineto |
|
150 | + 0 bh rlineto |
|
151 | + bw neg 0 rlineto |
|
152 | + closepath |
|
153 | + stroke |
|
154 | + end |
|
155 | +} def |
|
156 | + |
|
157 | +0.3 setlinewidth |
|
158 | + |
|
159 | +% 全体枠 |
|
160 | +0 0 moveto |
|
161 | +0 height lineto |
|
162 | +width height lineto |
|
163 | +width 0 lineto |
|
164 | +closepath |
|
165 | +0 0 0 1 setcmykcolor |
|
166 | +stroke |
|
167 | + |
|
168 | +%タイトル |
|
169 | +/KozGoPro-Medium-UniJIS-UTF8-H findfont 14 scalefont setfont |
|
170 | +tx ty moveto |
|
171 | +0 0 0 1 setcmykcolor |
|
172 | +(V圧着葉書テンプレート (宛名面)) show |
|
173 | + |
|
174 | +% 断ち落とし込みの領域 |
|
175 | +x2 y2 moveto x6 y2 lineto x6 y5 lineto x2 y5 lineto |
|
176 | +closepath |
|
177 | +1 0 0 0 setcmykcolor |
|
178 | +stroke |
|
179 | + |
|
180 | +% 断裁後の領域 |
|
181 | +x3 y3 moveto x5 y3 lineto x5 y4 lineto x3 y4 lineto |
|
182 | +closepath |
|
183 | +1 0 0 0 setcmykcolor |
|
184 | +stroke |
|
185 | + |
|
186 | +% トンボ |
|
187 | +x2 y1 moveto x2 y3 lineto x1 y3 lineto |
|
188 | +x3 y1 moveto x3 y2 lineto x1 y2 lineto |
|
189 | +x5 y1 moveto x5 y2 lineto x7 y2 lineto |
|
190 | +x6 y1 moveto x6 y3 lineto x7 y3 lineto |
|
191 | +x1 y4 moveto x2 y4 lineto x2 y6 lineto |
|
192 | +x1 y5 moveto x3 y5 lineto x3 y6 lineto |
|
193 | +x5 y6 moveto x5 y5 lineto x7 y5 lineto |
|
194 | +x6 y6 moveto x6 y4 lineto x7 y4 lineto |
|
195 | +x4 y1 moveto x4 y2 lineto |
|
196 | +x4 y5 moveto x4 y6 lineto |
|
197 | +0 0 0 1 setcmykcolor |
|
198 | +stroke |
|
199 | + |
|
200 | +% 郵便番号枠 |
|
201 | +0 1 1 0 setcmykcolor |
|
202 | + |
|
203 | +0.5 mm2point mul setlinewidth |
|
204 | +bx1 by1 drawBox |
|
205 | +bx2 by1 drawBox |
|
206 | +bx3 by1 drawBox |
|
207 | +0.3 mm2point mul setlinewidth |
|
208 | +bx4 by1 drawBox |
|
209 | +bx5 by1 drawBox |
|
210 | +bx6 by1 drawBox |
|
211 | +bx7 by1 drawBox |
|
212 | +0.5 mm2point mul setlinewidth |
|
213 | +bx8 by2 moveto bx4 by2 lineto |
|
214 | +stroke |
|
215 | + |
|
216 | +showpage |
|
217 | + |
|
218 | +% EOF |
|
219 | +``` |
|
220 | + |
|
221 | +## ダウンロード |
|
222 | +- EPSファイルとそれをAcrobat Distiller 6でPDFに変換したもの<br /> |
|
223 | +[VAH.zip](VAH.zip) |
|
224 | + |
|
225 | +~~#navi(Perl/EPSファイル作成)~~ |
|
... | ... | \ No newline at end of file |
Perl/EPS\343\203\225\343\202\241\343\202\244\343\203\253\344\275\234\346\210\220/\343\202\250\343\203\263\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260.md
... | ... | @@ -0,0 +1,144 @@ |
1 | +~~#navi(Perl/EPSファイル作成)~~ |
|
2 | +[[_TOC_]] |
|
3 | +# エンコーディングと文字列の原点 |
|
4 | +## 概要 |
|
5 | +- 使用しているフォントは「小塚ゴシック Pro - M」。 |
|
6 | +- EPS中で「Unicode(UTF8)」で指定する場合は「KozGoPro-Medium-UniJIS-UTF8-H」と記述する。(横書き) |
|
7 | +- EPS中で「Unicode(UCS2)」で指定する場合は「KozGoPro-Medium-UniJIS-UCS2-H」と記述する。(横書き) |
|
8 | +- EPS中で「Unicode(UTF8)」で指定する場合は「KozGoPro-Medium-UniJIS-UTF8-V」と記述する。(縦書き) |
|
9 | +- EPS中で「Unicode(UCS2)」で指定する場合は「KozGoPro-Medium-UniJIS-UCS2-V」と記述する。(縦書き) |
|
10 | + |
|
11 | +## ソースコード |
|
12 | +``` |
|
13 | +# EPS作成 |
|
14 | +# テキストの配置 |
|
15 | +# このソースは UTF8N, LF で保存すること |
|
16 | + |
|
17 | +use strict; |
|
18 | +use utf8; |
|
19 | +use Encode qw/encode decode/; |
|
20 | + |
|
21 | +my $eps_file = 'GA2.eps'; |
|
22 | +my $mm2point = 72 / 25.4; |
|
23 | + |
|
24 | +# A4サイズ |
|
25 | +my $width = sprintf( "%.2f", 210 * $mm2point ); |
|
26 | +my $height = sprintf( "%.2f", 297 * $mm2point ); |
|
27 | + |
|
28 | +my $String = "ギャラクシーエンジェる〜ん Oct 2006"; |
|
29 | +my $String_ucs2 = &str_to_ucs2( $String ); |
|
30 | +my $String_utf8 = &str_to_utf8( $String ); |
|
31 | +my $StringFontSize = 24; |
|
32 | + |
|
33 | +my $x1 = 4 * $StringFontSize; |
|
34 | +my $y1 = $height - 4 * $StringFontSize; |
|
35 | + |
|
36 | +my $x2 = $x1; |
|
37 | +my $y2 = $height - 6 * $StringFontSize; |
|
38 | + |
|
39 | +my $x3 = $x1; |
|
40 | +my $y3 = $height - 8 * $StringFontSize; |
|
41 | + |
|
42 | +my $x4 = 9 * $StringFontSize; |
|
43 | +my $y4 = $height - 11 * $StringFontSize; |
|
44 | + |
|
45 | +my $x5 = 13 * $StringFontSize; |
|
46 | +my $y5 = $y4; |
|
47 | + |
|
48 | +my $x6 = 17 * $StringFontSize; |
|
49 | +my $y6 = $y4; |
|
50 | + |
|
51 | +my $eps = ''; |
|
52 | + |
|
53 | +$eps .=<<EOL; |
|
54 | +%!PS-Adobe-3.0 EPSF-3.0 |
|
55 | +%%BoundingBox: 0 0 $width $height |
|
56 | + |
|
57 | +/putText { |
|
58 | + 4 dict begin |
|
59 | + /str exch def |
|
60 | + /encode exch def |
|
61 | + /ty exch def |
|
62 | + /tx exch def |
|
63 | + 0 1 1 0 setcmykcolor |
|
64 | + tx ty moveto |
|
65 | + tx ty 2 0 360 arc |
|
66 | + fill |
|
67 | + 0 0 0 1 setcmykcolor |
|
68 | + encode findfont $StringFontSize scalefont setfont |
|
69 | + tx ty moveto |
|
70 | + str show |
|
71 | + end |
|
72 | +} def |
|
73 | + |
|
74 | +% 全体枠 |
|
75 | +0 0 moveto |
|
76 | +0 $height lineto |
|
77 | +$width $height lineto |
|
78 | +$width 0 lineto |
|
79 | +closepath |
|
80 | +1 setlinewidth |
|
81 | +0 0 0 1 setcmykcolor |
|
82 | +stroke |
|
83 | + |
|
84 | +% 小塚ゴシック Pro - M |
|
85 | +$x1 $y1 /KozGoPro-Medium-UniJIS-UTF8-H <$String_utf8> putText |
|
86 | +$x2 $y2 /KozGoPro-Medium-UniJIS-UCS2-H <$String_ucs2> putText |
|
87 | +$x3 $y3 /KozGoPro-Medium-UniJIS-UCS2-HW-H <$String_ucs2> putText |
|
88 | +$x4 $y4 /KozGoPro-Medium-UniJIS-UTF8-V <$String_utf8> putText |
|
89 | +$x5 $y5 /KozGoPro-Medium-UniJIS-UCS2-V <$String_ucs2> putText |
|
90 | +$x6 $y6 /KozGoPro-Medium-UniJIS-UCS2-HW-V <$String_ucs2> putText |
|
91 | + |
|
92 | +showpage |
|
93 | +EOL |
|
94 | + |
|
95 | +open( OUT, ">:encoding(utf8)", $eps_file ) || die( "can't open '" . $eps_file . "'.\n" ); |
|
96 | +print OUT $eps; |
|
97 | +close( OUT ); |
|
98 | + |
|
99 | +exit(); |
|
100 | + |
|
101 | +#### Subroutine #### |
|
102 | + |
|
103 | +sub str_to_ucs2 |
|
104 | +{ |
|
105 | + my( $sIn ) = @_; |
|
106 | + my( $sOut, $len, $i ); |
|
107 | + |
|
108 | + $sOut = ''; |
|
109 | + |
|
110 | + $len = length( $sIn ); |
|
111 | + for( $i=0; $i<$len; ++$i ){ |
|
112 | + $sOut .= sprintf( "%04x ", unpack( "U", substr( $sIn, $i, 1 ))); |
|
113 | + } |
|
114 | + chop( $sOut ); |
|
115 | + |
|
116 | + return $sOut; |
|
117 | +} |
|
118 | + |
|
119 | +sub str_to_utf8 |
|
120 | +{ |
|
121 | + my( $sIn ) = @_; |
|
122 | + my( $sOut, $len, $i ); |
|
123 | + |
|
124 | + $sOut = ''; |
|
125 | + |
|
126 | + $len = length( $sIn ); |
|
127 | + for( $i=0; $i<$len; ++$i ){ |
|
128 | + $sOut .= unpack( "H8", substr( $sIn, $i, 1 ) ) . ' '; |
|
129 | + } |
|
130 | + chop( $sOut ); |
|
131 | + |
|
132 | + return $sOut; |
|
133 | +} |
|
134 | + |
|
135 | +# EOF |
|
136 | +``` |
|
137 | + |
|
138 | +## ダウンロード |
|
139 | +- ソースコードと出力されるEPSファイル<br /> |
|
140 | +[GA2.zip](GA2.zip) |
|
141 | +- EPSファイルをAcrobat Distiller 6でPDFに変換したもの<br /> |
|
142 | +[GA2.pdf](GA2.pdf) |
|
143 | + |
|
144 | +~~#navi(Perl/EPSファイル作成)~~ |
|
... | ... | \ No newline at end of file |
Perl/EPS\343\203\225\343\202\241\343\202\244\343\203\253\344\275\234\346\210\220/\346\226\207\345\255\227\343\201\256\345\233\236\350\273\242.md
... | ... | @@ -0,0 +1,111 @@ |
1 | +~~#navi(Perl/EPSファイル作成)~~ |
|
2 | +[[_TOC_]] |
|
3 | +# 文字の回転 |
|
4 | +## 概要 |
|
5 | +- 使用しているフォントは「小塚明朝 Std - M」。 |
|
6 | +- EPS中で「Unicode(UCS2)」で指定する場合は「KozMinStd-Medium-UniJIS-UCS2-V」と記述する。(縦書き) |
|
7 | +- EPS中で「Shift_JIS」で指定する場合は「KozMinStd-Medium-90ms-RKSJ-V」と記述する。(縦書き) |
|
8 | + |
|
9 | +## ソースコード |
|
10 | +``` |
|
11 | +# EPS作成 |
|
12 | +# テキストの配置 |
|
13 | +# このソースは UTF8N, LF で保存すること |
|
14 | + |
|
15 | +use strict; |
|
16 | +use utf8; |
|
17 | +use Encode qw/encode decode/; |
|
18 | + |
|
19 | +my $eps_file = 'Jugemu_u.eps'; |
|
20 | +my $mm2point = 72 / 25.4; |
|
21 | + |
|
22 | +# A4サイズ |
|
23 | +my $width = sprintf( "%.2f", 210 * $mm2point ); |
|
24 | +my $height = sprintf( "%.2f", 297 * $mm2point ); |
|
25 | + |
|
26 | +my $x0 = sprintf( "%.2f", $width / 2 ); |
|
27 | +my $y0 = sprintf( "%.2f", $height / 2 ); |
|
28 | + |
|
29 | +my $String = "寿限無 寿限無 五劫の擦り切れ 海砂利水魚の 水行末 雲来末 風来末 " |
|
30 | + . "食う寝る処に住む処 やぶら小路の藪柑子 パイポパイポ パイポのシューリンガン " |
|
31 | + . "シューリンガンのグーリンダイ グーリンダイのポンポコピーのポンポコナーの 長久命の長助"; |
|
32 | +my $StringFontSize = 32; |
|
33 | + |
|
34 | +my $Pi = 3.141592; |
|
35 | + |
|
36 | +my ( $len, $x, $y, $r, $theta, $i ); |
|
37 | + |
|
38 | +my $eps = ''; |
|
39 | + |
|
40 | +$eps .=<<EOL; |
|
41 | +%!PS-Adobe-3.0 EPSF-3.0 |
|
42 | +%%BoundingBox: 0 0 $width $height |
|
43 | + |
|
44 | +/putText { |
|
45 | + 4 dict begin |
|
46 | + /char exch def |
|
47 | + /angle exch def |
|
48 | + /ty exch def |
|
49 | + /tx exch def |
|
50 | + gsave |
|
51 | + tx ty translate |
|
52 | + angle rotate |
|
53 | + 0 0 moveto |
|
54 | + char show |
|
55 | + grestore |
|
56 | + end |
|
57 | +} def |
|
58 | + |
|
59 | +% 全体枠 |
|
60 | +0 0 moveto |
|
61 | +0 $height lineto |
|
62 | +$width $height lineto |
|
63 | +$width 0 lineto |
|
64 | +closepath |
|
65 | +1 setlinewidth |
|
66 | +0 0 0 1 setcmykcolor |
|
67 | +stroke |
|
68 | + |
|
69 | +% 小塚明朝 Std - M (縦書き) |
|
70 | +/KozMinStd-Medium-UniJIS-UCS2-V findfont $StringFontSize scalefont setfont |
|
71 | +0 0 0 1 setcmykcolor |
|
72 | + |
|
73 | +EOL |
|
74 | + |
|
75 | +$len = length( $String ); |
|
76 | +$r = $StringFontSize * 8; |
|
77 | +$theta = 0; |
|
78 | + |
|
79 | +for( $i=0; $i<$len; ++ $i ){ |
|
80 | + $x = $x0 + $r * cos( $theta ); |
|
81 | + $y = $y0 + $r * sin( $theta ); |
|
82 | + $eps .= sprintf( "%.2f %.2f %.1f <%04x> putText\n", |
|
83 | + $x, $y, $theta*180/$Pi, unpack("U",substr($String,$i,1)) ); |
|
84 | + $theta -= $StringFontSize * 1.05 / $r; |
|
85 | + if ( $theta < -2 * $Pi ){ |
|
86 | + $theta += 2 * $Pi; |
|
87 | + } |
|
88 | + $r -= $StringFontSize * $StringFontSize * 1.4 / ( 2 * $Pi * $r ); |
|
89 | +} |
|
90 | + |
|
91 | +$eps .=<<EOL; |
|
92 | + |
|
93 | +showpage |
|
94 | +EOL |
|
95 | + |
|
96 | +open( OUT, ">:encoding(utf8)", $eps_file ) || die( "can't open '" . $eps_file . "'.\n" ); |
|
97 | +print OUT $eps; |
|
98 | +close( OUT ); |
|
99 | + |
|
100 | +exit(); |
|
101 | + |
|
102 | +# EOF |
|
103 | +``` |
|
104 | + |
|
105 | +## ダウンロード |
|
106 | +- ソースコード(UCS2版, Shift_JIS版)と出力されるEPSファイル(UCS2版, Shift_JIS版)<br /> |
|
107 | +[Jugemu.zip](Jugemu.zip) |
|
108 | +- EPSファイルをAcrobat Distiller 6でPDFに変換したもの<br /> |
|
109 | +[Jugemu.pdf](Jugemu.pdf) |
|
110 | + |
|
111 | +~~#navi(Perl/EPSファイル作成)~~ |
|
... | ... | \ No newline at end of file |
Perl/EscapeSlash.md
... | ... | @@ -0,0 +1,124 @@ |
1 | +# C言語スタイルで文字列のエスケープ/アンエスケープを行う |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- 入力された文字列の中の改行など直接記述できない文字にバックスラッシュを付けてエスケープする。 |
|
6 | +- PHP関数 [addcslashes](http://jp2.php.net/manual/ja/%66%75%6e%63%74%69%6f%6e%2e%61%64%64%63%73%6c%61%73%68%65%73%2e%70%68%70) / [stripcslashes](http://jp2.php.net/manual/ja/%66%75%6e%63%74%69%6f%6e%2e%73%74%72%69%70%63%73%6c%61%73%68%65%73%2e%70%68%70) |
|
7 | +- 2つ目の引数にハッシュを指定することで別の変換を行うことができます。 |
|
8 | + - 書いたはいいが、2番目のパラメータをハッシュだと思い込んでたがホントは文字列だった。(--;)<br /> |
|
9 | +addcslashes, stripcslashes という関数名は付けられないなぁ。 |
|
10 | +- \xXX 形式には対応していません。 |
|
11 | + |
|
12 | +## ソースコード |
|
13 | +- [EscapeSlash.zip](EscapeSlash.zip) |
|
14 | + |
|
15 | +### EscapeSlash.pm |
|
16 | +``` |
|
17 | +# C言語スタイルで文字列のエスケープ/アンエスケープを行う |
|
18 | +# by TakeAsh |
|
19 | +# ネタ元 http://jp2.php.net/manual/ja/function.addcslashes.php |
|
20 | +# ネタ元 http://blog.livedoor.jp/dankogai/archives/50940023.html |
|
21 | +# |
|
22 | +# v0.00 2009.03.04 |
|
23 | +# v0.01 2009.03.12 空文字列が渡されたときはundefではなく空文字列を返すようにした。 |
|
24 | +# unescapeslashはescapeslashを呼ぶようにした。 |
|
25 | +# \e(0x1b)もエスケープするようにした。 |
|
26 | +# v0.02 2009.03.17 数値0が渡されたときに""ではなく0を返すようにした。 |
|
27 | +# v0.03 2009.08.14 ",'もエスケープするようにした。 |
|
28 | +# |
|
29 | +# 書いたはいいが、2番目のパラメータをハッシュだと思い込んでたがホントは文字列だった。(--;) |
|
30 | +# addcslashes, stripcslashes という関数名は付けられないなぁ。 |
|
31 | +# \xXX 形式には対応していません。 |
|
32 | + |
|
33 | +package EscapeSlash; |
|
34 | + |
|
35 | +use strict; |
|
36 | +use warnings; |
|
37 | +use utf8; |
|
38 | + |
|
39 | +use Exporter; |
|
40 | +our @ISA = qw(Exporter); |
|
41 | +our @EXPORT = qw(escapeslash unescapeslash); |
|
42 | + |
|
43 | +## スケープする文字セット |
|
44 | +my %charset_factory = ( |
|
45 | + "\\"=>"\\\\", "\n"=>"\\n", "\r"=>"\\r", "\t"=>"\\t", "\0"=>"\\0", |
|
46 | + "\a"=>"\\a", "\b"=>"\\b", "\f"=>"\\f", "\e" => "\\e", |
|
47 | + "\""=>"\\\"", "'"=>"\\'" |
|
48 | + # , "\v"=>"\\v" |
|
49 | +); |
|
50 | + |
|
51 | +## C言語スタイルで文字列のエスケープを行う |
|
52 | +# @param $str [in] 変換対象文字列 |
|
53 | +# @param %charset [in] エスケープする文字セット(オプション) |
|
54 | +# @return エスケープされた文字列 |
|
55 | +sub escapeslash{ |
|
56 | + my $str; |
|
57 | + $str = shift or return $str; # undef, "", 0 ならリターン |
|
58 | + my %charset = defined( $_[0] ) ? %{shift()} : %charset_factory ; # %{shift} だとハッシュへのリファレンスが受け取れない |
|
59 | + my $charclass = join( '|', map{ quotemeta } keys( %charset ) ); |
|
60 | + $str =~ s/($charclass)/$charset{$1}/msgex; |
|
61 | + return $str; |
|
62 | +} |
|
63 | + |
|
64 | +## C言語スタイルで文字列のアンエスケープを行う |
|
65 | +# @param $str [in] 変換対象文字列 |
|
66 | +# @param %charset [in] アンエスケープする文字セット(オプション) |
|
67 | +# @return アンエスケープされた文字列 |
|
68 | +sub unescapeslash{ |
|
69 | + my $str = shift; |
|
70 | + my %charset = defined( $_[0] ) ? %{shift()} : %charset_factory ; # %{shift} だとハッシュへのリファレンスが受け取れない |
|
71 | + %charset = reverse( %charset ); |
|
72 | + return escapeslash( $str, \%charset ); |
|
73 | +} |
|
74 | + |
|
75 | +1; |
|
76 | + |
|
77 | +# EOF |
|
78 | +``` |
|
79 | + |
|
80 | +### TestEscapeSlash.pl |
|
81 | +``` |
|
82 | +# EscapeSlash.pm の動作テスト |
|
83 | + |
|
84 | +use strict; |
|
85 | +use warnings; |
|
86 | +use utf8; |
|
87 | +use Data::Dump qw(dump); |
|
88 | + |
|
89 | +use EscapeSlash; |
|
90 | + |
|
91 | +my @Sample = ( |
|
92 | + "ab\\cd", "ab\ncd", "ab\rcd", "ab\tcd", "ab\0cd", "ab\"cd", "ab'cd", "ab?cd", "ab&cd", |
|
93 | + "ab\\\\cd", "ab\\ncd", "ab\\rcd", "ab\\tcd", "ab\\0cd", "ab\\\"cd", "ab\\'cd", "ab\\?cd", "ab\\&cd", |
|
94 | + "", undef, 0, "0", |
|
95 | +); |
|
96 | + |
|
97 | +my %ConvSet = ( "\\" => "\\\\", "?" => "\\?", "&"=>"\\&" ); |
|
98 | + |
|
99 | +my @TestData = ( @ARGV > 0 ) ? @ARGV : @Sample ; |
|
100 | + |
|
101 | +print "ConvSet for esc2,unesc2\n" . dump(%ConvSet)."\n\n"; |
|
102 | + |
|
103 | +foreach my $test ( @TestData ){ |
|
104 | + printf( "org:\t%s\n", dump($test) ); |
|
105 | + printf( "esc:\t%s\n", dump(escapeslash($test)) ); |
|
106 | + printf( "unesc:\t%s\n", dump(unescapeslash($test)) ); |
|
107 | + printf( "esc2:\t%s\n", dump(escapeslash($test,\%ConvSet)) ); |
|
108 | + printf( "unesc2:\t%s\n", dump(unescapeslash($test,\%ConvSet)) ); |
|
109 | + #printf( "Reverse:\t%d\n", $test eq unescapeslash(escapeslash($test)) ); |
|
110 | + print "\n"; |
|
111 | +} |
|
112 | + |
|
113 | +# EOF |
|
114 | +``` |
|
115 | + |
|
116 | +## Link |
|
117 | +- [[Microsoft SQL Server インポート/エクスポート|Perl/MSSQL_ImpExp]] |
|
118 | + |
|
119 | +- [勝手に添削 - 40行で作るPerl用テンプレートエンジン](http://blog.livedoor.jp/dankogai/archives/50940023.html) |
|
120 | +- [javascript - String.prototype.quotemeta() があればいいんじゃね?](http://blog.livedoor.jp/dankogai/archives/51058313.html) |
|
121 | +- [Perlメモ](http://www.din.or.jp/~ohzaki/perl.htm) / [改行コードを統一する](http://www.din.or.jp/~ohzaki/perl.htm#CRLF_Unify) |
|
122 | + |
|
123 | +- [perldoc.jp](http://perldoc.jp/) / [Perlのリファレンスとネストしたデータ構造](http://perldoc.jp/pod/perlref) / [あまりシンボリックではないリファレンス](http://perldoc.jp/pod/perlref#Not-so-symbolic32references) |
|
124 | + - perl のバージョン 5.001 で、中かっこに囲まれたシンボリックリファレンスが よりクォートのように、ちょうどそれが文字列の中にあるかのように 振る舞うという新たな機能が読みやすさのために追加されました。 |
|
... | ... | \ No newline at end of file |
Perl/GD.md
... | ... | @@ -0,0 +1,64 @@ |
1 | +# GDライブラリを使って画像の縮小版を作成する |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +GDライブラリを使って画像の 1/2, 1/3, 1/4 縮小版を一括で作成する。 |
|
6 | + |
|
7 | +## スクリプト |
|
8 | +- [shrink.zip](shrink.zip) |
|
9 | + |
|
10 | +## shrink.pl |
|
11 | +``` |
|
12 | +# 画像一括縮小 |
|
13 | +# 「PDATA」以下のpngファイルを1/2,1/3,1/4に縮小し「PDATA2」「PDATA3」「PDATA4」へ保存する。 |
|
14 | + |
|
15 | +use strict; |
|
16 | +use warnings; |
|
17 | +use utf8; |
|
18 | +use GD; |
|
19 | + |
|
20 | +my @filelist = <./PDATA/*.png>; |
|
21 | +# print join( "\n", @filelist ); |
|
22 | + |
|
23 | +my $filein; # 入力ファイル名 |
|
24 | +my $imgsrc; # 入力画像 |
|
25 | +my( $width, $height ); # 入力画像の幅と高さ |
|
26 | +my $num; # 画像ファイル数 |
|
27 | +my $cnt = 0; # カウンタ |
|
28 | + |
|
29 | +$num = scalar( @filelist ); |
|
30 | +$| = 1; |
|
31 | +foreach $filein ( @filelist ){ |
|
32 | + $imgsrc = GD::Image->new( $filein ) || die( $! ); |
|
33 | + ( $width, $height ) = $imgsrc->getBounds(); |
|
34 | + shrink( $filein, 2 ); |
|
35 | + shrink( $filein, 3 ); |
|
36 | + shrink( $filein, 4 ); |
|
37 | + printf STDERR ( "%d/%d\r", ++$cnt, $num ); |
|
38 | +} |
|
39 | +$| = 0; |
|
40 | + |
|
41 | +sub shrink |
|
42 | +{ |
|
43 | + my( $filein, $div ) = @_; |
|
44 | + my $fhout; # 出力ファイルハンドル |
|
45 | + my $imgdst; # 出力画像 |
|
46 | + my( $w2, $h2 ); # 出力画像の幅と高さ |
|
47 | + my $fileout; # 出力ファイル名 |
|
48 | + |
|
49 | + $w2 = int( $width / $div ); # intが無いとクラッシュする |
|
50 | + $h2 = int( $height / $div ); # intが無いとクラッシュする |
|
51 | + $imgdst = new GD::Image( $w2, $h2, 0 ); |
|
52 | + $imgdst->copyResized( $imgsrc, 0, 0, 0, 0, $w2, $h2, $width, $height ); |
|
53 | + $fileout = $filein; |
|
54 | + $fileout =~ s#/PDATA/#/PDATA${div}/#; |
|
55 | + open( $fhout, ">:bytes", $fileout ) || die( $! ); |
|
56 | + binmode( $fhout ); # ">:bytes" があればいらないはずだが、無いと読めないファイルが出来る。 |
|
57 | + print $fhout $imgdst->png; |
|
58 | + close( $fhout ); |
|
59 | +} |
|
60 | + |
|
61 | +# EOF |
|
62 | +``` |
|
63 | + |
|
64 | +## リンク |
|
... | ... | \ No newline at end of file |
Perl/GMTtoLocalTime.md
... | ... | @@ -0,0 +1,96 @@ |
1 | +# GMT からローカルタイム(JST)に変換 |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- GMT を [CPAN:HTTP-Date](http://search.cpan.org/dist/HTTP-Date) および Perl 標準機能のみを使ってローカルタイムに変換する。 |
|
6 | +- GMTtoLocal2 は時差の指定は無視する。 |
|
7 | + |
|
8 | +## ソース |
|
9 | +- [GMTtoLocal.zip](GMTtoLocal.zip) |
|
10 | +```perl |
|
11 | +#!/usr/bin/perl |
|
12 | +# GMT からローカルタイム(JST)に変換 |
|
13 | + |
|
14 | +use strict; |
|
15 | +use warnings; |
|
16 | +use utf8; |
|
17 | +use Encode; |
|
18 | +use HTTP::Date qw( time2str str2time time2iso ); |
|
19 | +use POSIX qw(strftime); |
|
20 | +use Time::Local; |
|
21 | + |
|
22 | +my $charsetConsole = 'CP932'; |
|
23 | +my $charsetFile = 'UTF-8'; |
|
24 | + |
|
25 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
26 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
27 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
28 | + |
|
29 | +my @sample = ( |
|
30 | + '2011-11-23T00:00:00Z', |
|
31 | + '2011-12-31T20:00:00Z', |
|
32 | + '2012-02-28T21:00:00+00:00', |
|
33 | + '2012-02-28T21:00:00+09:00', |
|
34 | +); |
|
35 | + |
|
36 | +foreach my $src ( @sample ){ |
|
37 | + printf( "Source\t\t%s\nHTTP::Date\t%s\nStandard\t%s\n\n", |
|
38 | + $src, GMTtoLocal1( $src ), GMTtoLocal2( $src ) ); |
|
39 | +} |
|
40 | + |
|
41 | +exit(); |
|
42 | + |
|
43 | +# HTTP::Date を使用 |
|
44 | +# http://search.cpan.org/dist/HTTP-Date/ |
|
45 | +sub GMTtoLocal1 |
|
46 | +{ |
|
47 | + my( $gmt ) = @_; |
|
48 | + return time2iso( str2time( $gmt, 'Asia/Tokyo' ) ); |
|
49 | +} |
|
50 | + |
|
51 | +# Perl標準機能のみ |
|
52 | +# http://chalow.net/2010-03-01-5.html |
|
53 | +# 時差の指定は無視して常にGMTと見なす。 |
|
54 | +sub GMTtoLocal2 |
|
55 | +{ |
|
56 | + my( $gmt ) = @_; |
|
57 | + my $ret = $gmt; |
|
58 | + if ( $gmt =~ /^(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)/ ){ |
|
59 | + my $utm = timegm( $6, $5, $4, $3, $2-1, $1 ); |
|
60 | + $ret = strftime( "%Y-%m-%d %H:%M:%S", localtime( $utm ) ); |
|
61 | + } |
|
62 | + return $ret; |
|
63 | +} |
|
64 | + |
|
65 | +# EOF |
|
66 | +``` |
|
67 | + |
|
68 | +## 出力 |
|
69 | +``` |
|
70 | +Source 2011-11-23T00:00:00Z |
|
71 | +HTTP::Date 2011-11-23 09:00:00 |
|
72 | +Standard 2011-11-23 09:00:00 |
|
73 | + |
|
74 | +Source 2011-12-31T20:00:00Z |
|
75 | +HTTP::Date 2012-01-01 05:00:00 |
|
76 | +Standard 2012-01-01 05:00:00 |
|
77 | + |
|
78 | +Source 2012-02-28T21:00:00+00:00 |
|
79 | +HTTP::Date 2012-02-29 06:00:00 |
|
80 | +Standard 2012-02-29 06:00:00 |
|
81 | + |
|
82 | +Source 2012-02-28T21:00:00+09:00 |
|
83 | +HTTP::Date 2012-02-28 21:00:00 |
|
84 | +Standard 2012-02-29 06:00:00 |
|
85 | +``` |
|
86 | + |
|
87 | +## リンク |
|
88 | +- [CPAN:HTTP-Date](http://search.cpan.org/dist/HTTP-Date) |
|
89 | +- [CPAN:Time-Local](http://search.cpan.org/dist/Time-Local) |
|
90 | +- [CPAN:Time-Piece](http://search.cpan.org/dist/Time-Piece) |
|
91 | + |
|
92 | +- [たつをの ChangeLog](http://chalow.net/) |
|
93 | + - [GMT による時間表現文字列を JST に変換する Perl コード片](http://chalow.net/2010-03-01-5.html) |
|
94 | + |
|
95 | +- [サンプルコードによるPerl入門](http://d.hatena.ne.jp/perlcodesample/) |
|
96 | + - [今月の最初の日を表すTime::Pieceオブジェクトを取得する / Time::Piece Tips](http://d.hatena.ne.jp/perlcodesample/20120911/1347331536) |
|
... | ... | \ No newline at end of file |
Perl/GoogleMapAPI.md
... | ... | @@ -0,0 +1,115 @@ |
1 | +# Google Map API を使って始点終点の経路情報と地図画像を得る |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- [Google Directions API](http://code.google.com/intl/ja/apis/maps/documentation/directions/)を使って経路情報を得る。 |
|
6 | +- [Static Maps API](http://code.google.com/intl/ja/apis/maps/documentation/staticmaps/)を使って経路情報付き画像を得る。 |
|
7 | +- 事前にカレントディレクトリに保存用ディレクトリ「map」を作成しておく必要がある。 |
|
8 | +- 使用例 |
|
9 | +``` |
|
10 | +>gmap.pl 東京 ビックサイト |
|
11 | +>gmap.pl 東京 サンフランシスコ |
|
12 | +``` |
|
13 | + |
|
14 | +## ソース |
|
15 | +- [gmap.pl](gmap.pl) |
|
16 | +``` |
|
17 | +#!/usr/bin/perl |
|
18 | +# gmap.pl |
|
19 | +# 始点終点の経路情報と地図画像を得る。 |
|
20 | +# 使用法: gmap.pl <始点> <終点> |
|
21 | + |
|
22 | +use strict; |
|
23 | +use warnings; |
|
24 | +use utf8; |
|
25 | +use Encode; |
|
26 | +use LWP::UserAgent; |
|
27 | +use HTTP::Request; |
|
28 | +use JSON; |
|
29 | +use YAML::Syck; |
|
30 | + |
|
31 | +my $GoogleMapDirectionsAPI = 'http://maps.google.com/maps/api/directions/json?mode=walking&language=ja&sensor=false'; |
|
32 | +my $GoogleMapStaticAPI = 'http://maps.google.com/maps/api/staticmap?size=640x640&language=ja&sensor=false'; |
|
33 | +my $MapPath = './map/'; |
|
34 | + |
|
35 | +$YAML::Syck::ImplicitUnicode = 1; |
|
36 | + |
|
37 | +binmode( STDIN, ":encoding(CP932)" ); |
|
38 | +binmode( STDOUT, ":encoding(CP932)" ); |
|
39 | +binmode( STDERR, ":encoding(CP932)" ); |
|
40 | + |
|
41 | +my $usStart = decode( 'CP932', shift ); # unicode string |
|
42 | +my $usGoal = decode( 'CP932', shift ); # unicode string |
|
43 | +if ( !defined( $usStart ) || $usStart eq "" || !defined( $usGoal ) || $usGoal eq "" ){ |
|
44 | + die( "使用法: $0 <始点> <終点>\n" ); |
|
45 | +} |
|
46 | + |
|
47 | +my $esStart = encodeURIComponent( $usStart ); # encoded string |
|
48 | +my $esGoal = encodeURIComponent( $usGoal ); # encoded string |
|
49 | +my $usFName = $usStart . '_' . $usGoal; # unicode string |
|
50 | +my $bsFName = encode( 'CP932', $MapPath . $usFName ); # byte string |
|
51 | + |
|
52 | +#printf( "start:\t%s\t%s\ngoal:\t%s\t%s\n", $usStart, $esStart, $usGoal, $esGoal ); |
|
53 | + |
|
54 | +my $ua = LWP::UserAgent->new( keep_alive => 2 ); |
|
55 | + |
|
56 | +my $res = $ua->get( $GoogleMapDirectionsAPI . '&origin=' . $esStart . '&destination=' . $esGoal ); |
|
57 | +if ( $res->is_success ){ |
|
58 | + #print $res->content, "\n"; |
|
59 | + # http://www.donzoko.net/cgi-bin/tdiary/20100406.html#p01 |
|
60 | + my $json = JSON->new->utf8; |
|
61 | + my $usRoute = $json->decode( $res->content ); |
|
62 | + #print Dump( $usRoute ); |
|
63 | + if ( $usRoute->{'status'} eq 'OK' ){ |
|
64 | + my $usLegs = $usRoute->{'routes'}[0]{'legs'}[0]; |
|
65 | + #delete $usLegs->{'steps'}; |
|
66 | + open( my $fout, ">:utf8", $bsFName . '.yaml' ) or die( "$usFName: $!\n" ); |
|
67 | + print $fout Dump( $usLegs ); |
|
68 | + close( $fout ); |
|
69 | + |
|
70 | + my $start_lat = $usLegs->{'start_location'}{'lat'}; |
|
71 | + my $start_lng = $usLegs->{'start_location'}{'lng'}; |
|
72 | + my $end_lat = $usLegs->{'end_location'}{'lat'}; |
|
73 | + my $end_lng = $usLegs->{'end_location'}{'lng'}; |
|
74 | + my $center_lng = ( $start_lng + $end_lng ) / 2; |
|
75 | + if ( $start_lng * $end_lng < 0 && abs( $start_lng ) + abs( $end_lng ) > 180 ){ |
|
76 | + if ( $center_lng >= 0 ){ |
|
77 | + $center_lng -= 180; |
|
78 | + } else { |
|
79 | + $center_lng += 180; |
|
80 | + } |
|
81 | + } |
|
82 | + my $mapURI = $GoogleMapStaticAPI |
|
83 | + . '¢er=' . (( $start_lat + $end_lat ) / 2 ) . ',' . $center_lng |
|
84 | + . '&markers=label:S|' . $start_lat . ',' . $start_lng |
|
85 | + . '&markers=label:G|' . $end_lat . ',' . $end_lng |
|
86 | + . '&path=enc:' . $usRoute->{'routes'}[0]{'overview_polyline'}{'points'}; |
|
87 | + $ua->request( HTTP::Request->new( GET => $mapURI ), $bsFName . '.png' ); |
|
88 | + } else { |
|
89 | + die( "Error: $usRoute->{'status'}\n" ); |
|
90 | + } |
|
91 | +} else { |
|
92 | + die( "Error: $res->status_line\n" ); |
|
93 | +} |
|
94 | + |
|
95 | +sub encodeURIComponent { |
|
96 | + my $str = encode( 'utf-8', shift ); |
|
97 | + $str =~ s/([^0-9A-Za-z!'()*\-._~])/sprintf("%%%02X", ord($1))/eg; |
|
98 | + return $str; |
|
99 | +} |
|
100 | + |
|
101 | +# EOF |
|
102 | +``` |
|
103 | + |
|
104 | +## リンク |
|
105 | +- [[JavaScript/GoogleMapAPI]] |
|
106 | + |
|
107 | +- [Google Maps API ファミリー - Google Code](http://code.google.com/intl/ja/apis/maps/) |
|
108 | + - [Google Directions API](http://code.google.com/intl/ja/apis/maps/documentation/directions/) |
|
109 | + - [Static Maps API](http://code.google.com/intl/ja/apis/maps/documentation/staticmaps/) |
|
110 | + |
|
111 | +- [CPAN:JSON-XS](http://search.cpan.org/dist/JSON-XS) |
|
112 | +- [CPAN:URI](http://search.cpan.org/dist/URI) (URI::Escape) |
|
113 | + |
|
114 | +- [どんぞこCGI+--](http://www.donzoko.net/) / [どんぞこ日誌](http://www.donzoko.net/cgi-bin/tdiary/) / [JSONのドキュメントに追加した部分](http://www.donzoko.net/cgi-bin/tdiary/20100406.html#p01) |
|
115 | +- [rubyu備忘録](http://d.hatena.ne.jp/ruby-U/) / [perlとpython用encodeURIComponent()](http://d.hatena.ne.jp/ruby-U/20081110/1226313786) |
|
... | ... | \ No newline at end of file |
Perl/HTTP\343\202\242\343\202\257\343\202\273\343\202\271.md
... | ... | @@ -0,0 +1,81 @@ |
1 | +# HTTPアクセス |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 情報源 |
|
5 | + |
|
6 | +~[ActivePerl](http://www.activestate.com/ActivePerl/)には、[libwww-perl](http://lwp.linpro.no/lwp/)がパッケージとして含まれているので、ローカルの Perl/html/site/lib/lwpcook.html を参照すること。 |
|
7 | + |
|
8 | +## サンプル |
|
9 | +- [TinyProxy.zip](TinyProxy.zip) |
|
10 | +```perl |
|
11 | +#!/usr/bin/perl |
|
12 | +# TinyProxy.pl |
|
13 | +# コマンドラインで指定した URI を utf8 としてファイルに保存。 |
|
14 | + |
|
15 | +use strict; |
|
16 | +use warnings; |
|
17 | +use utf8; |
|
18 | +use Encode; |
|
19 | +use LWP::UserAgent; |
|
20 | +#use URI::Escape; |
|
21 | +use EscapeSlash; |
|
22 | + |
|
23 | +my $charsetConsole = 'CP932'; |
|
24 | +my $charsetFile = 'UTF-8'; |
|
25 | + |
|
26 | +# ファイル名/パス名として使用できない文字+α |
|
27 | +my %ConvSet = map{ $_ => '%' . uc( unpack( 'H02', $_ ) ) } split( //, '\\/*?|<>:,;% \"' ); |
|
28 | + |
|
29 | +@ARGV = map{ decode( $charsetConsole, $_ ); } @ARGV; |
|
30 | + |
|
31 | +my $url = $ARGV[0] or die( "usage: TinyProxy.pl <URI>\n" ); |
|
32 | +my $fileNameOut = $url; |
|
33 | +if ( $fileNameOut =~ m#^.*/$# ){ |
|
34 | + $fileNameOut .= 'index.html'; |
|
35 | +} |
|
36 | +$fileNameOut =~ s#^\w+://(.*)$#$1#; |
|
37 | +#$fileNameOut = uri_escape_utf8( $fileNameOut ); |
|
38 | +$fileNameOut = escapeslash( $fileNameOut, \%ConvSet ); |
|
39 | + |
|
40 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
41 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
42 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
43 | + |
|
44 | +open( my $OUT, ">:encoding($charsetFile)", encode( $charsetConsole, $fileNameOut ) ) |
|
45 | + or die( "$fileNameOut: $!\n" ); |
|
46 | +print $OUT getURI( $url ); |
|
47 | +close( $OUT ); |
|
48 | + |
|
49 | +exit(); |
|
50 | + |
|
51 | +# --- Subroutine --- |
|
52 | +sub getURI { |
|
53 | + my( $URI ) = @_; |
|
54 | + |
|
55 | + my $ua = LWP::UserAgent->new; |
|
56 | + my $req = HTTP::Request->new( GET => $URI ); |
|
57 | + |
|
58 | + # send request |
|
59 | + my $res = $ua->request( $req ); |
|
60 | + |
|
61 | + # check the outcome |
|
62 | + if ( $res->is_success ){ |
|
63 | + return $res->decoded_content; # utf8フラグ付テキスト |
|
64 | + } else { |
|
65 | + return "Error: " . $res->status_line . "\n"; |
|
66 | + } |
|
67 | +} |
|
68 | + |
|
69 | +# EOF |
|
70 | +``` |
|
71 | + |
|
72 | +## リンク |
|
73 | +- [[Perl/EscapeSlash]] |
|
74 | +- [[Perl/nicoget]] |
|
75 | + |
|
76 | +- [CPAN:libwww-perl](http://search.cpan.org/dist/libwww-perl) |
|
77 | +- [CPAN:HTTP-Message](http://search.cpan.org/dist/HTTP-Message) |
|
78 | +- [libwww-perl](http://lwp.linpro.no/lwp/) |
|
79 | +- [CPAN:URI/URI/Escape.pm](http://search.cpan.org/dist/URI/URI/Escape.pm) |
|
80 | + |
|
81 | +- [LWP::UserAgentでdecoded_contentしたら特定のContent-Typeで文字化けするのでハックした](http://blog.livedoor.jp/sasata299/archives/51212133.html) @ [(゚∀゚)o彡 sasata299's blog](http://blog.livedoor.jp/sasata299/) |
|
... | ... | \ No newline at end of file |
Perl/Home.md
... | ... | @@ -1,3 +1,32 @@ |
1 | -# Perl |
|
1 | +[[_TOC_]] |
|
2 | 2 | |
3 | -- [[Http]] |
|
3 | +# サンプルスクリプト |
|
4 | +~~#ls2()~~ |
|
5 | +- [GitHub:TakeAsh/p-usDownload](https://github.com/TakeAsh/p-usDownload) Ustream Archive Downloader |
|
6 | +- [GitHub:TakeAsh/p-RecRadiru](https://github.com/TakeAsh/p-RecRadiru) NHK Net Radio らじる★らじる を rtmpdump で録音するスクリプト |
|
7 | + |
|
8 | +# リンク |
|
9 | +- http://perldoc.jp/ |
|
10 | + - [コアドキュメント](http://perldoc.jp/index/core) |
|
11 | + - [組み込み関数](http://perldoc.jp/index/function) |
|
12 | + - [翻訳済モジュール](http://perldoc.jp/index/module) |
|
13 | + |
|
14 | +- [The CPAN Search Site](http://search.cpan.org/) |
|
15 | +- [スマートスマート](http://www.rfs.jp/) / [Perl講座](http://www.rfs.jp/sb/perl/) |
|
16 | +- [ActiveState Tool Corp.](https://www.activestate.com/) |
|
17 | + - [ActivePerl](https://www.activestate.com/activeperl/) |
|
18 | + - [ActivePerl Documentation](https://docs.activestate.com/activeperl/) |
|
19 | + - [ActivePerl 5.24 Documentation](https://docs.activestate.com/activeperl/5.24/) / [Release Notes](https://docs.activestate.com/activeperl/5.24/release.html) / [PPM, Proxies and Firewalls](https://docs.activestate.com/activeperl/5.24/faq/ActivePerl-faq2.html#ppm_and_proxies) |
|
20 | + - [ActivePerl 5.22 Documentation](https://docs.activestate.com/activeperl/5.22/) / [Release Notes](https://docs.activestate.com/activeperl/5.22/release.html) / [PPM, Proxies and Firewalls](https://docs.activestate.com/activeperl/5.22/faq/ActivePerl-faq2.html#ppm_and_proxies) |
|
21 | + - [ActivePerl 5.20 Documentation](https://docs.activestate.com/activeperl/5.20/) / [Release Notes](https://docs.activestate.com/activeperl/5.20/release.html) / [PPM, Proxies and Firewalls](https://docs.activestate.com/activeperl/5.20/faq/ActivePerl-faq2.html#ppm_and_proxies) |
|
22 | + - [ActivePerl 5.18 Documentation](https://docs.activestate.com/activeperl/5.18/) / [Release Notes](https://docs.activestate.com/activeperl/5.18/release.html) / [PPM, Proxies and Firewalls](https://docs.activestate.com/activeperl/5.18/faq/ActivePerl-faq2.html#ppm_and_proxies) |
|
23 | + - [ActivePerl 5.16 Documentation](https://docs.activestate.com/activeperl/5.16/) / [Release Notes](https://docs.activestate.com/activeperl/5.16/release.html) / [PPM, Proxies and Firewalls](https://docs.activestate.com/activeperl/5.16/faq/ActivePerl-faq2.html#ppm_and_proxies) |
|
24 | + - [ActivePerl 5.14 Documentation](https://docs.activestate.com/activeperl/5.14/) / [Release Notes](https://docs.activestate.com/activeperl/5.14/release.html) |
|
25 | + - [ActivePerl 5.12 Documentation](https://docs.activestate.com/activeperl/5.12/) / [Release Notes](https://docs.activestate.com/activeperl/5.12/release.html) |
|
26 | + - [ActivePerl 5.10 Documentation](https://docs.activestate.com/activeperl/5.10/) |
|
27 | + - [ActivePerl 5.8 Documentation](https://docs.activestate.com/activeperl/5.8/) |
|
28 | +- [Perl入門@ITpro](http://itpro.nikkeibp.co.jp/article/COLUMN/20080528/304529/) |
|
29 | +- [Perlリファレンス@ITpro](http://itpro.nikkeibp.co.jp/article/Reference/20081111/318984/) |
|
30 | + - [目的別インデックス](http://itpro.nikkeibp.co.jp/article/Reference/20080926/315520/) |
|
31 | + - [関数順インデックス](http://itpro.nikkeibp.co.jp/article/Reference/20080926/315499/) |
|
32 | +- [Perlでフォトショップ CS](http://www2.tba.t-com.ne.jp/tail/prog/perl/photoshop.html) @ [Storeroom](http://www2.tba.t-com.ne.jp/tail/) |
Perl/HostToIP.md
... | ... | @@ -0,0 +1,45 @@ |
1 | +# HostToIP |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- ホスト名からIPアドレスを求め、IPアドレスからホスト名を逆引きする。 |
|
6 | + |
|
7 | +## ソース |
|
8 | +- [HostToIP.zip](HostToIP.zip) |
|
9 | +```perl |
|
10 | +#!/usr/bin/perl |
|
11 | +# HostToIP.pl |
|
12 | +# ホスト名からIPアドレスを求める。(IPv4) |
|
13 | +# さらにIPアドレスからホスト名を逆引きする。 |
|
14 | + |
|
15 | +use strict; |
|
16 | +use warnings; |
|
17 | +use utf8; |
|
18 | +use Encode; |
|
19 | +use Socket; |
|
20 | + |
|
21 | +my $charsetConsole = 'CP932'; |
|
22 | +#my $charsetConsole = 'UTF-8'; |
|
23 | +my $charsetFile = 'UTF-8'; |
|
24 | + |
|
25 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
26 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
27 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
28 | + |
|
29 | +@ARGV = map{ decode( $charsetConsole, $_ ); } @ARGV; |
|
30 | + |
|
31 | +my $host1 = $ARGV[0] || 'localhost'; |
|
32 | +my $ipn = inet_aton( $host1 ); |
|
33 | +my $ipa = inet_ntoa( $ipn ); |
|
34 | +my $host2 = gethostbyaddr( $ipn, AF_INET ); |
|
35 | + |
|
36 | +print "$host1\n$ipa\n$host2\n"; |
|
37 | + |
|
38 | +# EOF |
|
39 | +``` |
|
40 | + |
|
41 | +## リンク |
|
42 | +- [[Perl/getHostName]] |
|
43 | + |
|
44 | +- [CPAN:Socket](http://search.cpan.org/dist/Socket) |
|
45 | +- [CPAN:Socket6](http://search.cpan.org/dist/Socket6) |
|
... | ... | \ No newline at end of file |
Perl/Http.md
... | ... | @@ -1,3 +0,0 @@ |
1 | -# HTTP |
|
2 | - |
|
3 | -- HTTP アクセス |
Perl/HttpHeader.md
... | ... | @@ -0,0 +1,45 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# 概要 |
|
4 | +- 指定 URL のレスポンスの HTTP Header を表示する。 |
|
5 | + |
|
6 | +# ソース |
|
7 | +- [showHeaders.zip](showHeaders.zip) |
|
8 | +```perl |
|
9 | +#!/usr/bin/perl |
|
10 | +# HTTP Header の表示 |
|
11 | + |
|
12 | +use strict; |
|
13 | +use warnings; |
|
14 | +use utf8; |
|
15 | +use Encode; |
|
16 | +use LWP::UserAgent; |
|
17 | + |
|
18 | +#my $charsetConsole = 'UTF-8'; # Linux |
|
19 | +my $charsetConsole = 'CP932'; # Windows |
|
20 | +my $charsetFile = 'UTF-8'; |
|
21 | + |
|
22 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
23 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
24 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
25 | + |
|
26 | +my $url = $ARGV[0] or die("usage: showHeaders.pl <URL>\n"); |
|
27 | + |
|
28 | +my $ua = LWP::UserAgent->new; |
|
29 | +my $req = HTTP::Request->new( HEAD => $url ); |
|
30 | + |
|
31 | +# send request |
|
32 | +my $res = $ua->request($req); |
|
33 | +if ( !$res->is_success ) { |
|
34 | + die( "Error: " . $res->status_line . "\n" ); |
|
35 | +} |
|
36 | +foreach my $field ( sort( $res->header_field_names ) ) { |
|
37 | + printf( "%s\t%s\n", $field, $res->header($field) ); |
|
38 | +} |
|
39 | + |
|
40 | +# EOF |
|
41 | +``` |
|
42 | + |
|
43 | +# リンク |
|
44 | +- [CPAN:libwww-perl](http://search.cpan.org/dist/libwww-perl) |
|
45 | +- [CPAN:HTTP-Message](http://search.cpan.org/dist/HTTP-Message) |
|
... | ... | \ No newline at end of file |
Perl/IP\343\202\242\343\203\211\343\203\254\343\202\271\347\257\204\345\233\262\343\202\222\343\203\236\343\202\271\343\202\257\350\241\250\347\217\276\343\201\253\345\244\211\346\217\233.md
... | ... | @@ -0,0 +1,161 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# 概要 |
|
4 | +- [IP List for PeerGuardian 2](http://iplist.wave.prohosting.com/)のIPアドレス情報(IP1 - IP2)をマスク表現(IP/mask)に変換します。 |
|
5 | +- IP List for PeerGuardian 2 が公開されなくなったのね。 |
|
6 | +- Net::IP 使わないけど、[世界の国別 IPv4 アドレス割り当てリスト](http://nami.jp/ipv4bycc/)から国別の IP アドレスを抽出するスクリプトを作成。(2013/04/11) |
|
7 | + |
|
8 | +# ソース |
|
9 | +## makeIPBlockList.pl |
|
10 | +- [makeIPBlockList.zip](makeIPBlockList.zip) |
|
11 | +```perl |
|
12 | +#!/usr/bin/perl |
|
13 | +# makeIPBlockList.pl |
|
14 | +# http://iplist.wave.prohosting.com/ のIPリストから接続をブロックするIPアドレスのリストを作成する。 |
|
15 | + |
|
16 | +use strict; |
|
17 | +use warnings; |
|
18 | +use utf8; |
|
19 | +use Encode; |
|
20 | +use Net::IP; |
|
21 | + |
|
22 | +my $fileNameIn = "cn.txt"; |
|
23 | +my $fileNameOut = "cn_block.txt"; |
|
24 | + |
|
25 | +binmode( STDIN, ":encoding(CP932)" ); |
|
26 | +binmode( STDOUT, ":encoding(CP932)" ); |
|
27 | +binmode( STDERR, ":encoding(CP932)" ); |
|
28 | + |
|
29 | +$| = 1; |
|
30 | + |
|
31 | +open( my $fin, "<:utf8", encode( 'CP932', $fileNameIn ) ) or die( "$fileNameIn: $!\n" ); |
|
32 | +my @body = <$fin>; |
|
33 | +close( $fin ); |
|
34 | +chomp( @body ); |
|
35 | + |
|
36 | +open( my $fout, ">:utf8", encode( 'CP932', $fileNameOut ) ) or die( "$fileNameOut: $!\n" ); |
|
37 | + |
|
38 | +my $max = scalar( @body ); |
|
39 | +my $count = 0; |
|
40 | + |
|
41 | +while( @body > 0 ){ |
|
42 | + printf STDERR ( "%d/%d\r", ++$count, $max ); |
|
43 | + my $line = shift( @body ); |
|
44 | + if ( $line =~ /[^:]+:(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)/ ){ |
|
45 | + my $ip = new Net::IP( "$1-$2" ) or die( Net::IP::Error() ); |
|
46 | + foreach ( $ip->find_prefixes() ){ |
|
47 | + /([^\/]+)\/([^\/]+)/; |
|
48 | + printf $fout ( "%s/%s\n", $1, makeMask( $2 ) ); |
|
49 | + } |
|
50 | + } |
|
51 | +} |
|
52 | + |
|
53 | +close( $fout ); |
|
54 | + |
|
55 | +sub makeMask |
|
56 | +{ |
|
57 | + my( $x ) = @_; |
|
58 | + my $ret = ''; |
|
59 | + my $b = "1"; |
|
60 | + while( $x > 0 ){ |
|
61 | + if ( $x & 1 ){ |
|
62 | + $ret .= $b; |
|
63 | + } |
|
64 | + $b .= $b; |
|
65 | + $x >>= 1; |
|
66 | + } |
|
67 | + return join( '.', unpack( 'C*', pack( 'B32', substr( $ret . "00000000000000000000000000000000", 0, 32 ) ) ) ); |
|
68 | +} |
|
69 | + |
|
70 | +# EOF |
|
71 | +``` |
|
72 | + |
|
73 | +### 入力 |
|
74 | +``` |
|
75 | +CN:58.14.0.0-58.25.255.255 |
|
76 | +CN:58.30.0.0-58.63.255.255 |
|
77 | +CN:58.66.0.0-58.67.255.255 |
|
78 | +CN:58.68.128.0-58.68.255.255 |
|
79 | +CN:58.82.0.0-58.83.255.255 |
|
80 | +CN:58.87.64.0-58.87.127.255 |
|
81 | +CN:58.99.128.0-58.101.255.255 |
|
82 | +CN:58.116.0.0-58.119.255.255 |
|
83 | +CN:58.128.0.0-58.135.255.255 |
|
84 | +CN:58.144.0.0-58.144.255.255 |
|
85 | +``` |
|
86 | + |
|
87 | +### 出力 |
|
88 | +``` |
|
89 | +58.14.0.0/255.254.0.0 |
|
90 | +58.16.0.0/255.248.0.0 |
|
91 | +58.24.0.0/255.254.0.0 |
|
92 | +58.30.0.0/255.254.0.0 |
|
93 | +58.32.0.0/255.224.0.0 |
|
94 | +58.66.0.0/255.254.0.0 |
|
95 | +58.68.128.0/255.255.128.0 |
|
96 | +58.82.0.0/255.254.0.0 |
|
97 | +58.87.64.0/255.255.192.0 |
|
98 | +58.99.128.0/255.255.128.0 |
|
99 | +58.100.0.0/255.254.0.0 |
|
100 | +58.116.0.0/255.252.0.0 |
|
101 | +58.128.0.0/255.248.0.0 |
|
102 | +58.144.0.0/255.255.0.0 |
|
103 | +``` |
|
104 | + |
|
105 | +## makeIPBlockList2.pl |
|
106 | +- [makeIPBlockList2.zip](makeIPBlockList2.zip) |
|
107 | +```perl |
|
108 | +#!/usr/bin/perl |
|
109 | +# makeIPBlockList2.pl |
|
110 | +# http://nami.jp/ipv4bycc/mask.txt からアクセス禁止国のIPアドレスを抽出 |
|
111 | + |
|
112 | +use strict; |
|
113 | +use warnings; |
|
114 | +use utf8; |
|
115 | +use Encode; |
|
116 | + |
|
117 | +#my $charset_console = 'UTF-8'; |
|
118 | +my $charset_console = 'CP932'; |
|
119 | +my $charset_file = 'UTF-8'; |
|
120 | + |
|
121 | +binmode( STDIN, ":encoding($charset_console)" ); |
|
122 | +binmode( STDOUT, ":encoding($charset_console)" ); |
|
123 | +binmode( STDERR, ":encoding($charset_console)" ); |
|
124 | + |
|
125 | +my $fileNameIn = 'mask.txt'; |
|
126 | +my $fileNameOut = 'block_list.txt'; |
|
127 | + |
|
128 | +my @countries = qw( CN KR RU BR ); |
|
129 | +my $block_countries = '^(' . join( "|", map{ quotemeta($_); } @countries ) . ')$'; |
|
130 | + |
|
131 | +open( my $fin, "<:encoding($charset_file)", encode( $charset_console, $fileNameIn ) ) |
|
132 | + or die( "$fileNameIn: $!\n" ); |
|
133 | +open( my $fout, ">:encoding($charset_file)", encode( $charset_console, $fileNameOut ) ) |
|
134 | + or die( "$fileNameOut: $!\n" ); |
|
135 | + |
|
136 | +foreach my $line ( <$fin> ){ |
|
137 | + my( $country, $ip ) = split( /\s/, $line ); |
|
138 | + if ( $country =~ /$block_countries/i ){ |
|
139 | + #$ip =~ s{/}{,}; |
|
140 | + printf $fout ( "%s\n", $ip ); |
|
141 | + } |
|
142 | +} |
|
143 | + |
|
144 | +close( $fin ); |
|
145 | +close( $fout ); |
|
146 | + |
|
147 | +# EOF |
|
148 | +``` |
|
149 | + |
|
150 | +# リンク |
|
151 | +- [CPAN:Net-IP](http://search.cpan.org/dist/Net-IP) |
|
152 | + |
|
153 | +- [Office Nami](http://nami.jp/) |
|
154 | + - [世界の国別 IPv4 アドレス割り当てリスト](http://nami.jp/ipv4bycc/) |
|
155 | +- [IP List for PeerGuardian 2](http://iplist.wave.prohosting.com/) |
|
156 | +- [PeerGuardian](http://peerguardian.sourceforge.net/) |
|
157 | + |
|
158 | +- [Perlの数値変換](http://mikeneko.creator.club.ne.jp/~lab/perl/numerical_transform/) |
|
159 | + |
|
160 | +- [iptab と ipcount](http://tkoshima.net/wp/archives/350) |
|
161 | +- [IPCount Tool](http://www.ripe.net/cgi-bin/wwwipcount.cgi) |
|
... | ... | \ No newline at end of file |
Perl/ListDownloader.md
... | ... | @@ -0,0 +1,57 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# 概要 |
|
4 | +- 1行に1つ URL が書かれたファイルにしたがって該当ファイルをダウンロードする。 |
|
5 | +- リストファイルがあるフォルダにダウンロードしたファイルを保存する。 |
|
6 | +- アクセス結果を表示するよう変更。(2016-09-12) |
|
7 | + |
|
8 | +# ソース |
|
9 | +- [ListDownloader.zip](ListDownloader.zip) |
|
10 | +```perl |
|
11 | +use strict; |
|
12 | +use warnings; |
|
13 | +use utf8; |
|
14 | +use Encode; |
|
15 | +use File::Basename; |
|
16 | +use File::chdir; |
|
17 | +use LWP::UserAgent; |
|
18 | +use HTTP::Request; |
|
19 | + |
|
20 | +my $charsetConsole = $^O eq 'MSWin32' ? 'CP932' : 'UTF-8'; |
|
21 | + |
|
22 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
23 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
24 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
25 | + |
|
26 | +@ARGV = map { decode( $charsetConsole, $_ ); } @ARGV; |
|
27 | + |
|
28 | +my $charsetFile = 'UTF-8'; |
|
29 | +my $ioLayer = $^O eq 'MSWin32' ? "raw:encoding($charsetFile):crlf" : "encoding($charsetFile)"; |
|
30 | +my $listFile = $ARGV[0] or die("usage: ListDownloader <list file>\n"); |
|
31 | +$CWD = dirname( encode( $charsetConsole, $listFile ) ); |
|
32 | +open( my $fin, "<:$ioLayer", encode( $charsetConsole, $listFile ) ) |
|
33 | + or die("$listFile: $!\n"); |
|
34 | +my @lines = <$fin>; |
|
35 | +close($fin); |
|
36 | +chomp(@lines); |
|
37 | +my %listHash = map { $_ => 1 } @lines; |
|
38 | +my @list = sort( keys(%listHash) ); |
|
39 | + |
|
40 | +my $ua = LWP::UserAgent->new( keep_alive => 4 ); |
|
41 | +$ua->cookie_jar( {} ); |
|
42 | + |
|
43 | +my $count = 0; |
|
44 | +my $max = scalar(@list); |
|
45 | +foreach my $url (@list) { |
|
46 | + ++$count; |
|
47 | + $url =~ m{([^\/]+)$}; |
|
48 | + my $filename = $1; |
|
49 | + print "$count/$max\t$filename\n"; |
|
50 | + my $res |
|
51 | + = $ua->request( HTTP::Request->new( GET => $url ), encode( $charsetConsole, $filename ) ); |
|
52 | + sleep(1); |
|
53 | +} |
|
54 | +``` |
|
55 | + |
|
56 | +# リンク |
|
57 | +- [CPAN:perl/lib/File/Basename.pm](http://search.cpan.org/dist/perl/lib/File/Basename.pm) |
|
... | ... | \ No newline at end of file |
Perl/MSSQL_ImpExp.md
... | ... | @@ -0,0 +1,464 @@ |
1 | +# Microsoft SQL Server インポート/エクスポート |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- MS SQL Server のテーブルを CSV ファイル(K3フォーマット)としてインポート/エクスポートする。 |
|
6 | +- 第1フィールドをプライマリフィールドとして、レコードが未登録か登録済みかを判別し、INSERT または UPDATE を行なう。 |
|
7 | +- NULLは「NULL」として書き出される。文字列としてのNULLは「"NULL"」になる。 |
|
8 | +- INDEX(オートナンバー)制約があるフィールドには未対応(ハングアップする)。(2011/09/28) |
|
9 | + |
|
10 | +## ソースコード |
|
11 | +- [MSSQL_ImpExp.zip](MSSQL_ImpExp.zip) |
|
12 | + |
|
13 | +### DB_Connect.yaml |
|
14 | +``` |
|
15 | +# DB接続情報 |
|
16 | +Driver: ODBC |
|
17 | +Server: localhost\SQLEXPRESS,1433 # <サーバ名>\<インスタンス名>[,<ポート番号>] |
|
18 | +User: TestUser |
|
19 | +Password: "TestPass" # 記号を含む場合は""で括る。 |
|
20 | +DB: TestDB |
|
21 | +Options: |
|
22 | + LongTruncOk: 1 |
|
23 | + LongReadLen: 8192 |
|
24 | +DSN: _Driver_:Driver={SQL Server}; Server={_Server_}; Database=_DB_; |
|
25 | +``` |
|
26 | + |
|
27 | +### getSchema.pl |
|
28 | +```perl |
|
29 | +#!/usr/bin/perl |
|
30 | +# MSSQLサーバからスキーマを読み出す |
|
31 | + |
|
32 | +use strict; |
|
33 | +use warnings; |
|
34 | +use utf8; |
|
35 | +use Encode; |
|
36 | +use YAML::Syck; |
|
37 | +use FindBin::libs; |
|
38 | +use DBIx::NamedParams; |
|
39 | + |
|
40 | +$YAML::Syck::ImplicitUnicode = 1; |
|
41 | + |
|
42 | +my $charsetConsole = 'CP932'; |
|
43 | +my $charsetFile = 'UTF-8'; |
|
44 | + |
|
45 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
46 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
47 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
48 | + |
|
49 | +my $DB_Connect_yaml = './DB_Connect.yaml'; |
|
50 | +my $DB_Schema_yaml = './DB_Schema.yaml'; |
|
51 | + |
|
52 | +my @SchemaColumns = qw( |
|
53 | + COLUMN_NAME DATA_TYPE CHARACTER_MAXIMUM_LENGTH COLUMN_DEFAULT IS_NULLABLE |
|
54 | +); |
|
55 | + |
|
56 | +$| = 1; |
|
57 | + |
|
58 | +my $Schemas = {}; |
|
59 | + |
|
60 | +my $DB_Connect = YAML::Syck::LoadFile( $DB_Connect_yaml ) |
|
61 | + or die( "$DB_Connect_yaml: $!" ); |
|
62 | +foreach( keys( %{$DB_Connect} ) ){ |
|
63 | + $DB_Connect->{'DSN'} =~ s/_${_}_/$DB_Connect->{$_}/; |
|
64 | +} |
|
65 | +#print Dump( $DB_Connect ); |
|
66 | +#exit; |
|
67 | + |
|
68 | +my $dbh = DBI->connect( |
|
69 | + "DBI:" . $DB_Connect->{'DSN'}, |
|
70 | + $DB_Connect->{'User'}, |
|
71 | + $DB_Connect->{'Password'}, |
|
72 | + $DB_Connect->{'Options'} |
|
73 | +) or die( "$DBI::errstr\n" ); |
|
74 | +#print Dump( $dbh ); |
|
75 | +#exit; |
|
76 | + |
|
77 | +my $DBName = $DB_Connect->{'DB'}; |
|
78 | +my $sql_getTables = qq{ |
|
79 | + SELECT [TABLE_NAME] |
|
80 | + FROM [INFORMATION_SCHEMA].[TABLES] |
|
81 | + WHERE [TABLE_CATALOG] = '$DBName' |
|
82 | + and [TABLE_TYPE]='BASE TABLE' |
|
83 | + ORDER BY [TABLE_NAME]; |
|
84 | +}; |
|
85 | +my $sth = $dbh->prepare( $sql_getTables ) or die( "$DBI::errstr\n" ); |
|
86 | +$sth->execute() or die( "$DBI::errstr\n" ); |
|
87 | + |
|
88 | +do { |
|
89 | + while( my @a = $sth->fetchrow_array ){ |
|
90 | + #printf( "%s\n", join( "\t", @a ) ); |
|
91 | + $Schemas->{ $a[0] } = []; |
|
92 | + } |
|
93 | +}while( $sth->{odbc_more_results} ); |
|
94 | +$sth->finish; |
|
95 | + |
|
96 | +my @TableNames = sort( keys( %{ $Schemas } ) ); |
|
97 | +#print "Tables: " . scalar(@TableNames) ."\n"; |
|
98 | +#print join( "\n", DBIx::NamedParams::all_sql_types() ) . "\n"; |
|
99 | +#exit; |
|
100 | + |
|
101 | +$_ = '[' . join( "], [", @SchemaColumns ) . ']'; |
|
102 | +my $sql_getColumns = qq{ |
|
103 | + SELECT $_ |
|
104 | + FROM [INFORMATION_SCHEMA].[COLUMNS] |
|
105 | + WHERE [TABLE_CATALOG] = '$DBName' |
|
106 | + and [TABLE_NAME] = :TableName-WVARCHAR |
|
107 | +}; |
|
108 | +$sth = $dbh->prepare_ex( $sql_getColumns ) or die( "$DBI::errstr\n" ); |
|
109 | + |
|
110 | +my $count = 0; |
|
111 | +foreach my $tbl ( @TableNames ){ |
|
112 | + printf( "%d/%d\t%s\n", ++$count, scalar(@TableNames), $tbl ); |
|
113 | + my @columns = (); |
|
114 | + $sth->bind_param_ex( { 'TableName' => $tbl } ); |
|
115 | + $sth->execute() or die( "$DBI::errstr\n" ); |
|
116 | + do { |
|
117 | + while( my @a = $sth->fetchrow_array ){ |
|
118 | + #printf( "%s\n", join( "\t", @a ) ); |
|
119 | + my $ColumnsInfo = {}; |
|
120 | + for( my $i=0; $i<@SchemaColumns; ++$i ){ |
|
121 | + $ColumnsInfo->{ $SchemaColumns[ $i ] } = $a[ $i ]; |
|
122 | + } |
|
123 | + push( @columns, $ColumnsInfo ); |
|
124 | + } |
|
125 | + }while( $sth->{odbc_more_results} ); |
|
126 | + $Schemas->{ $tbl } = [ @columns ]; |
|
127 | +} |
|
128 | +$sth->finish; |
|
129 | + |
|
130 | +$dbh->disconnect; |
|
131 | + |
|
132 | +open( my $fhout, ">:utf8", encode( $charsetConsole, $DB_Schema_yaml ) ) |
|
133 | + or die( "$DB_Schema_yaml: $!\n" ); |
|
134 | +print $fhout YAML::Syck::Dump( $Schemas ); |
|
135 | +#print dump( $Schemas ); |
|
136 | +close( $fhout ); |
|
137 | + |
|
138 | +# EOF |
|
139 | +``` |
|
140 | + |
|
141 | +### getTbl.pl |
|
142 | +```perl |
|
143 | +#!/usr/bin/perl |
|
144 | +# MSSQLサーバからデータ読み出し |
|
145 | + |
|
146 | +use strict; |
|
147 | +use warnings; |
|
148 | +use utf8; |
|
149 | +use Encode; |
|
150 | +use YAML::Syck; |
|
151 | +use FindBin::libs; |
|
152 | +use DBIx::NamedParams; |
|
153 | +use EscapeSlash; |
|
154 | + |
|
155 | +$YAML::Syck::ImplicitUnicode = 1; |
|
156 | + |
|
157 | +my $charsetConsole = 'CP932'; |
|
158 | +my $charsetFile = 'UTF-8'; |
|
159 | + |
|
160 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
161 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
162 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
163 | + |
|
164 | +my $DB_Connect_yaml = './DB_Connect.yaml'; |
|
165 | +my $DB_Tables_yaml = './DB_Schema.yaml'; |
|
166 | + |
|
167 | +# ""で括る文字列型 |
|
168 | +my $StrType = join( "|", qw( |
|
169 | + CHAR GUID UNKNOWN_TYPE VARCHAR WCHAR WLONGVARCHAR WVARCHAR |
|
170 | +) ); |
|
171 | + |
|
172 | +my $DB_Connect = YAML::Syck::LoadFile( $DB_Connect_yaml ) |
|
173 | + or die( "$DB_Connect_yaml: $!\n" ); |
|
174 | +foreach( %{$DB_Connect} ){ |
|
175 | + $DB_Connect->{'DSN'} =~ s/_${_}_/$DB_Connect->{$_}/; |
|
176 | +} |
|
177 | +#print dump( $DB_Connect ); |
|
178 | + |
|
179 | +my $DB_Tables = YAML::Syck::LoadFile( $DB_Tables_yaml ) |
|
180 | + or die( "$DB_Tables_yaml: $!\n" ); |
|
181 | +#print dump( $DB_Tables ); |
|
182 | +my @DB_TableNames = sort( keys( %{$DB_Tables} ) ); |
|
183 | + |
|
184 | +my $dbh = DBI->connect( |
|
185 | + "DBI:" . $DB_Connect->{'DSN'}, |
|
186 | + $DB_Connect->{'User'}, |
|
187 | + $DB_Connect->{'Password'}, |
|
188 | + $DB_Connect->{'Options'} |
|
189 | +) or die( "$DBI::errstr\n" ); |
|
190 | + |
|
191 | +my %DrvTypeToSQLType = $dbh->driver_typename_map(); |
|
192 | + |
|
193 | +my $count=0; |
|
194 | +my $TableNum = scalar(@DB_TableNames); |
|
195 | + |
|
196 | +foreach my $tbl ( @DB_TableNames ){ |
|
197 | + printf STDERR ( "%d/%d\t%s\n", ++$count, $TableNum, $tbl ); |
|
198 | + my @FieldName = map { ${$_ }{'COLUMN_NAME'}; } @{ $DB_Tables->{ $tbl } }; |
|
199 | + my @DataType = map { ${$_ }{'DATA_TYPE'}; } @{ $DB_Tables->{ $tbl } }; |
|
200 | + |
|
201 | + my $sql = "SELECT [" . join( "],[", @FieldName ) . "] FROM [$tbl];"; |
|
202 | + my $sth = $dbh->prepare( $sql ) or die( "$DBI::errstr\n" ); |
|
203 | + $sth->execute() or die( "$DBI::errstr\n" ); |
|
204 | + |
|
205 | + my $fout = './_DB/' . $tbl . '.txt'; |
|
206 | + open( my $fhout, ">:encoding($charsetFile)", encode( $charsetConsole, $fout ) ) |
|
207 | + or die( "$fout: $!\n" ); |
|
208 | + |
|
209 | + printf $fhout ( "\"%s\"\n", join( "\"\t\"", @FieldName ) ); |
|
210 | + do { |
|
211 | + while( my @a = $sth->fetchrow_array ){ |
|
212 | + for( my $i=0; $i<@a; ++$i ){ |
|
213 | + no warnings 'uninitialized'; |
|
214 | + $a[$i] =~ s/\x00//g; |
|
215 | + #$a[$i] =~ s/[\r\n\t]+$//; |
|
216 | + $a[$i] = escapeslash( $a[$i] ); |
|
217 | + if ( !defined($a[$i]) ){ |
|
218 | + # NULL だったら |
|
219 | + $a[$i] = "NULL"; |
|
220 | + } elsif ( $DrvTypeToSQLType{ $DataType[$i] } =~ /$StrType/ ){ |
|
221 | + # 文字列ならば |
|
222 | + $a[$i] = '"' . $a[$i] . '"'; |
|
223 | + } |
|
224 | + } |
|
225 | + printf $fhout ( "%s\n", join( "\t", @a ) ); |
|
226 | + } |
|
227 | + }while( $sth->{odbc_more_results} ); |
|
228 | + $sth->finish; |
|
229 | + |
|
230 | + close( $fhout ); |
|
231 | +} |
|
232 | + |
|
233 | +$dbh->disconnect; |
|
234 | + |
|
235 | +# EOF |
|
236 | +``` |
|
237 | + |
|
238 | +### setTbl.pl |
|
239 | +```perl |
|
240 | +#!/usr/bin/perl |
|
241 | +# MSSQLサーバへデータ書込み |
|
242 | +# 2011/09/28 オートナンバー型非対応 |
|
243 | + |
|
244 | +use strict; |
|
245 | +use warnings; |
|
246 | +use utf8; |
|
247 | +use Encode; |
|
248 | +use YAML::Syck; |
|
249 | +use FindBin::libs; |
|
250 | +use DBIx::NamedParams; |
|
251 | +use EscapeSlash; |
|
252 | + |
|
253 | +$YAML::Syck::ImplicitUnicode = 1; |
|
254 | + |
|
255 | +my $charsetConsole = 'CP932'; |
|
256 | +my $charsetFile = 'UTF-8'; |
|
257 | + |
|
258 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
259 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
260 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
261 | + |
|
262 | +my $DB_Connect_yaml = './DB_Connect.yaml'; |
|
263 | +my $DB_Tables_yaml = './DB_Schema.yaml'; |
|
264 | + |
|
265 | +my $DB_Connect = YAML::Syck::LoadFile( $DB_Connect_yaml ) |
|
266 | + or die( "$DB_Connect_yaml: $!" ); |
|
267 | +foreach( %{$DB_Connect} ){ |
|
268 | + $DB_Connect->{'DSN'} =~ s/_${_}_/$DB_Connect->{$_}/; |
|
269 | +} |
|
270 | +#print Dump( $DB_Connect ); |
|
271 | + |
|
272 | +my $DB_Tables = YAML::Syck::LoadFile( $DB_Tables_yaml ) |
|
273 | + or die( "$DB_Tables_yaml: $!" ); |
|
274 | +#print Dump( $DB_Tables ); |
|
275 | +my @DB_TableNames = keys( %{$DB_Tables} ); |
|
276 | + |
|
277 | +my $dbh = DBI->connect( |
|
278 | + "DBI:" . $DB_Connect->{'DSN'}, |
|
279 | + $DB_Connect->{'User'}, |
|
280 | + $DB_Connect->{'Password'}, |
|
281 | + $DB_Connect->{'Options'} |
|
282 | +) or die( "$DBI::errstr\n" ); |
|
283 | + |
|
284 | +#DBIx::NamedParams::debug_log( 'MSSQL_ImpExp.log' ); |
|
285 | + |
|
286 | +my %DrvTypeToSQLType = $dbh->driver_typename_map(); |
|
287 | + |
|
288 | +my $count=0; |
|
289 | +my $TableNum = scalar(@DB_TableNames); |
|
290 | +my $fNoLocalize = 0; |
|
291 | + |
|
292 | +foreach my $tbl ( @DB_TableNames ){ |
|
293 | + ++$count; |
|
294 | + print "$count/$TableNum\t$tbl\n"; |
|
295 | + my( @field_org, @field_len, @field_type, @field_name_type, @field_prm ); |
|
296 | + foreach ( @{ $DB_Tables->{ $tbl } } ){ |
|
297 | + my $column_name = ${ $_ }{'COLUMN_NAME'}; |
|
298 | + my $data_type = ${ $_ }{'DATA_TYPE'}; |
|
299 | + my $name_type = ":$column_name-" . $DrvTypeToSQLType{ $data_type }; |
|
300 | + push( @field_org, $column_name ); |
|
301 | + push( @field_type, $data_type ); |
|
302 | + push( @field_len, ${ $_ }{'CHARACTER_MAXIMUM_LENGTH'} ); |
|
303 | + push( @field_name_type, $name_type ); |
|
304 | + push( @field_prm, "[$column_name]=$name_type" ); |
|
305 | + } |
|
306 | + my $i = 0; |
|
307 | + my %FN2I = map{ s/^"(.*)"$/$1/; $_ => $i++; } @field_org; |
|
308 | + #print Dump( \%FN2I ); |
|
309 | + |
|
310 | + my $FieldList = "[" . join( "],[", @field_org ) . "]"; |
|
311 | + my $ValueList = join( ",", @field_name_type ); |
|
312 | + my $UpdateList = join( ",", @field_prm ); |
|
313 | + |
|
314 | + my $PrimaryFieldName = $field_org[0]; |
|
315 | + my $PrimaryFieldNameType = $field_name_type[0]; |
|
316 | + my $sql_InsOrUpd = qq{ |
|
317 | + IF NOT EXISTS ( |
|
318 | + SELECT $FieldList |
|
319 | + FROM [$tbl] |
|
320 | + WHERE [$PrimaryFieldName] = $PrimaryFieldNameType |
|
321 | + ) |
|
322 | + BEGIN |
|
323 | + INSERT INTO [$tbl] |
|
324 | + ($FieldList) |
|
325 | + VALUES ($ValueList) |
|
326 | + END |
|
327 | + ELSE |
|
328 | + BEGIN |
|
329 | + UPDATE [$tbl] |
|
330 | + SET $UpdateList |
|
331 | + WHERE [$PrimaryFieldName] = $PrimaryFieldNameType |
|
332 | + END; |
|
333 | + }; |
|
334 | + #warn "$sql_InsOrUpd\n"; |
|
335 | + #exit(); |
|
336 | + |
|
337 | + my $sth = $dbh->prepare_ex( $sql_InsOrUpd ) |
|
338 | + or die( "$DBI::errstr\n" ); |
|
339 | + |
|
340 | + my $fin = './_DB/' . $tbl . '.txt'; |
|
341 | + open( my $fhin, "<:encoding($charsetFile)", encode( $charsetConsole, $fin ) ) |
|
342 | + or die( "$fin: $!\n" ); |
|
343 | + <$fhin>; # ヘッダ行を捨てる |
|
344 | + my @DB_Body = <$fhin>; |
|
345 | + close( $fhin ); |
|
346 | + chomp( @DB_Body ); |
|
347 | + |
|
348 | + foreach my $row ( @DB_Body ){ |
|
349 | + #warn $row."\n"; |
|
350 | + my @param = split( "\t", $row ); |
|
351 | + map{ if( /^NULL$/i ){ undef($_) } else { s/^"(.*)"$/$1/; } } @param; |
|
352 | + for( my $i=0; $i<@param; ++$i ){ |
|
353 | + if ( |
|
354 | + $field_len[ $i ] && ( $field_len[ $i ] > 0 ) |
|
355 | + && $param[ $i ] && ( length( $param[ $i ] ) > $field_len[ $i ] ) |
|
356 | + ){ |
|
357 | + print "Too long. ID:$param[0], $field_org[$i]: $param[$i]\n"; |
|
358 | + $param[ $i ] = substr( $param[ $i ], 0, $field_len[ $i ] ); |
|
359 | + } |
|
360 | + } |
|
361 | + my %bind = (); |
|
362 | + for( my $i=0; $i<@field_org; ++$i ){ |
|
363 | + $bind{ $field_org[ $i ] } = unescapeslash( $param[ $i ] ); |
|
364 | + } |
|
365 | + #print Dump( \%bind ) ."\n"; |
|
366 | + $sth->bind_param_ex( \%bind ); |
|
367 | + #exit(); |
|
368 | + $sth->execute() or die( "$DBI::errstr\n" ); |
|
369 | + } |
|
370 | + $sth->finish; |
|
371 | +} |
|
372 | +$dbh->disconnect; |
|
373 | + |
|
374 | +# EOF |
|
375 | +``` |
|
376 | + |
|
377 | +### makeTable.sql |
|
378 | +``` |
|
379 | +USE [TestDB] |
|
380 | +GO |
|
381 | + |
|
382 | +/****** Object: Table [dbo].[会員Table] Script Date: 08/15/2009 04:13:13 ******/ |
|
383 | +SET ANSI_NULLS ON |
|
384 | +GO |
|
385 | + |
|
386 | +SET QUOTED_IDENTIFIER ON |
|
387 | +GO |
|
388 | + |
|
389 | +CREATE TABLE [dbo].[会員Table]( |
|
390 | + [ID] [int] NOT NULL, |
|
391 | + [姓] [nvarchar](50) NOT NULL, |
|
392 | + [名] [nvarchar](50) NOT NULL, |
|
393 | + [誕生日] [date] NOT NULL, |
|
394 | + [性別] [int] NOT NULL, |
|
395 | + [Email] [nvarchar](50) NULL, |
|
396 | + [電話番号] [nvarchar](50) NULL, |
|
397 | + [郵便番号] [nvarchar](8) NULL, |
|
398 | + [住所1] [nvarchar](max) NULL, |
|
399 | + [住所2] [nvarchar](max) NULL, |
|
400 | + [クラスレベル] [int] NOT NULL, |
|
401 | + [前回ログイン] [datetime] NULL, |
|
402 | + [備考] [nvarchar](max) NULL, |
|
403 | + CONSTRAINT [PK_会員Table] PRIMARY KEY CLUSTERED |
|
404 | +( |
|
405 | + [ID] ASC |
|
406 | +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] |
|
407 | +) ON [PRIMARY] |
|
408 | + |
|
409 | +GO |
|
410 | + |
|
411 | +/****** Object: Table [dbo].[性別Table] Script Date: 08/15/2009 04:13:59 ******/ |
|
412 | +SET ANSI_NULLS ON |
|
413 | +GO |
|
414 | + |
|
415 | +SET QUOTED_IDENTIFIER ON |
|
416 | +GO |
|
417 | + |
|
418 | +CREATE TABLE [dbo].[性別Table]( |
|
419 | + [ID] [int] NOT NULL, |
|
420 | + [性別] [nvarchar](10) NOT NULL, |
|
421 | + CONSTRAINT [PK_性別Table] PRIMARY KEY CLUSTERED |
|
422 | +( |
|
423 | + [ID] ASC |
|
424 | +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] |
|
425 | +) ON [PRIMARY] |
|
426 | + |
|
427 | +GO |
|
428 | + |
|
429 | +/****** Object: Table [dbo].[クラスレベルTable] Script Date: 08/15/2009 04:14:09 ******/ |
|
430 | +SET ANSI_NULLS ON |
|
431 | +GO |
|
432 | + |
|
433 | +SET QUOTED_IDENTIFIER ON |
|
434 | +GO |
|
435 | + |
|
436 | +CREATE TABLE [dbo].[クラスレベルTable]( |
|
437 | + [ID] [int] NOT NULL, |
|
438 | + [クラスレベル] [nvarchar](30) NOT NULL, |
|
439 | + CONSTRAINT [PK_クラスレベルTable] PRIMARY KEY CLUSTERED |
|
440 | +( |
|
441 | + [ID] ASC |
|
442 | +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] |
|
443 | +) ON [PRIMARY] |
|
444 | + |
|
445 | +GO |
|
446 | +``` |
|
447 | + |
|
448 | +## Link |
|
449 | +- [[MS SQL Server|MSSQLSrv]] |
|
450 | +- [[Perl/EscapeSlash]] |
|
451 | +- [[Perl/DBIx-NamedParams]] |
|
452 | +- [[Perl/キーワード置換]] |
|
453 | + |
|
454 | +- [SQL Server - 情報スキーマ ビュー](http://msdn.microsoft.com/ja-jp/library/ms186778.aspx) |
|
455 | + - [TABLES](http://msdn.microsoft.com/ja-jp/library/ms186224.aspx) |
|
456 | + - [COLUMNS](http://msdn.microsoft.com/ja-jp/library/ms188348.aspx) |
|
457 | +- [sys.columns](http://msdn.microsoft.com/ja-jp/library/ms176106.aspx) |
|
458 | +- [データ型](http://msdn.microsoft.com/ja-jp/library/ms187752.aspx) |
|
459 | + |
|
460 | +- [MDB生成/テーブル定義取得ツール](http://www.asahi-net.or.jp/~ef2o-inue/download/sub09_010_070.html) |
|
461 | + |
|
462 | +- [「IDENTITY属性を持つ列を探すには」をお題にやったことをBlogる](http://d.hatena.ne.jp/CAMUSs_BLACKBOARD/20040618) @ [CAMUS’s BLACKBOARD](http://d.hatena.ne.jp/CAMUSs_BLACKBOARD/) |
|
463 | +``` |
|
464 | +EXEC sp_MShelpcolumns [テーブル名] |
|
... | ... | \ No newline at end of file |
Perl/MailForm.md
... | ... | @@ -0,0 +1,333 @@ |
1 | +[[_TOC_]] |
|
2 | +---- |
|
3 | +# 概要 |
|
4 | +- ファイルが添付できるメールフォーム。 |
|
5 | +- 宛先は config.yaml で指定する。フォームから宛先の追加も可能。 |
|
6 | +- 名前, 宛先は Cookie に保存される。(1ヶ月) |
|
7 | +- アクセス元のホスト名を表示。 |
|
8 | +- cookie の path を設定。 |
|
9 | + |
|
10 | +# ソース |
|
11 | +- [MailForm.zip](MailForm.zip) |
|
12 | + |
|
13 | +## index.cgi |
|
14 | +```perl |
|
15 | +#!/usr/bin/perl |
|
16 | +# MailForm |
|
17 | +# Web フォームから入力されたコメントとファイルを、 |
|
18 | +# 特定の Email アドレスへ添付ファイル付きで送信する。 |
|
19 | + |
|
20 | +use strict; |
|
21 | +use warnings; |
|
22 | +use utf8; |
|
23 | +use Encode; |
|
24 | +use YAML::Syck; |
|
25 | +use JSON::Syck; |
|
26 | +use FindBin; |
|
27 | +use CGI::Pretty qw( -no_xhtml *table ); # //HTML 4.01 Transitional//EN |
|
28 | +use CGI::Cookie; |
|
29 | +use Email::Sender::Simple qw( sendmail ); |
|
30 | +use Email::Sender::Transport::SMTP; |
|
31 | +use Email::MIME; |
|
32 | +use Email::MIME::Creator; |
|
33 | +use Net::DNS::Resolver; |
|
34 | + |
|
35 | +$YAML::Syck::ImplicitUnicode = 1; |
|
36 | +$YAML::Syck::ImplicitTyping = 1; |
|
37 | +$YAML::Syck::Headless = 1; |
|
38 | +$JSON::Syck::ImplicitUnicode = 1; |
|
39 | + |
|
40 | +my $charset_console = 'UTF-8'; |
|
41 | +my $charset_file = 'UTF-8'; |
|
42 | +my $charset_input = 'UTF-8'; |
|
43 | + |
|
44 | +#binmode( STDIN, ":encoding($charset_console)" ); # バイナリファイルが化ける |
|
45 | +binmode( STDIN, ":raw" ); # バイナリファイルをアップロードする場合に必要 |
|
46 | +binmode( STDOUT, ":encoding($charset_console)" ); |
|
47 | +binmode( STDERR, ":encoding($charset_console)" ); |
|
48 | + |
|
49 | +my $base_path = $FindBin::RealBin . '/'; |
|
50 | +my $config_file = $base_path . 'config.yaml'; |
|
51 | +my $cgi_name = 'MailForm'; |
|
52 | +my $cookie_name = $cgi_name; |
|
53 | + |
|
54 | +my $q = new CGI; |
|
55 | +$q->charset( $charset_console ); |
|
56 | +my $br = $q->br(); |
|
57 | + |
|
58 | +$JSON::Syck::ImplicitUnicode = 1; |
|
59 | +my $cookies = CGI::Cookie->fetch; |
|
60 | +my $cookie = ( $cookies && $cookies->{$cookie_name} ) |
|
61 | + ? JSON::Syck::Load( $cookies->{$cookie_name}->value || '{}' ) |
|
62 | + : {} ; |
|
63 | +# クッキーにゴミデータが入っていた場合に消去 |
|
64 | +if ( ref( $cookie ) ne 'HASH' ){ |
|
65 | + $cookie = {}; |
|
66 | +} |
|
67 | + |
|
68 | +my $config = YAML::Syck::LoadFile( $config_file ) or die( "$config_file: $!\n" ); |
|
69 | + |
|
70 | +my $command = $q->param( 'Command' ) || ''; |
|
71 | +my $comment = decode( $charset_input, $q->param( 'Comment' ) || '' ); |
|
72 | +my $file_name = $q->param( 'Attachment' ) || ''; |
|
73 | +my $file_type = $q->uploadInfo( $file_name ) |
|
74 | + ? $q->uploadInfo( $file_name )->{ 'Content-Type' } || '' |
|
75 | + : ''; |
|
76 | +$file_name = decode( $charset_input, $file_name ); |
|
77 | +my $file_body = ''; |
|
78 | +if ( my $lightweight_fh = $q->upload( 'Attachment' ) ){ |
|
79 | + my $io_handle = $lightweight_fh->handle; |
|
80 | + while ( my $bytesread = $io_handle->read( my $buffer, 1024 ) ){ |
|
81 | + $file_body .= $buffer; |
|
82 | + } |
|
83 | +} |
|
84 | +my $user_name = decode( $charset_input, $q->param( 'UserName' ) || '' ) |
|
85 | + || $cookie->{ 'UserName' } || ''; |
|
86 | +my $user_email = decode( $charset_input, $q->param( 'UserEmail' ) || '' ) |
|
87 | + || $cookie->{ 'UserEmail' } || ''; |
|
88 | + |
|
89 | +$cookie = { |
|
90 | + 'UserName' => $user_name, |
|
91 | + 'UserEmail' => $user_email, |
|
92 | +}; |
|
93 | + |
|
94 | +my $remote_ip = $ENV{ 'REMOTE_ADDR' }; |
|
95 | +my $remote_name = getHostName( $remote_ip ); |
|
96 | + |
|
97 | +print makeHeader(); |
|
98 | +if ( $command eq 'doPost' ){ |
|
99 | + my $mail_result; |
|
100 | + if ( length( $file_body ) > 0 ){ |
|
101 | + $mail_result = sendMail(); |
|
102 | + } |
|
103 | + print showPostedInfo(); |
|
104 | +} else { |
|
105 | + print makeForm(); |
|
106 | +} |
|
107 | +print makeFooter(); |
|
108 | + |
|
109 | +exit; |
|
110 | + |
|
111 | +sub makeHeader |
|
112 | +{ |
|
113 | + my $ret = ''; |
|
114 | + $JSON::Syck::ImplicitUnicode = 0; |
|
115 | + my $cookie_header = CGI::Cookie->new( |
|
116 | + -name => $cookie_name, |
|
117 | + -value => JSON::Syck::Dump( $cookie ), |
|
118 | + -expires => '+1M', |
|
119 | + -path => $ENV{'REQUEST_URI'}, |
|
120 | + ); |
|
121 | + $ret .= $q->header( -cookie => [ $cookie_header ] ); |
|
122 | + $ret .= $q->start_html( |
|
123 | + -title => $cgi_name, |
|
124 | + -lang => 'ja-JP', |
|
125 | + -head => [ |
|
126 | + $q->meta( { -http_equiv => 'Content-style-type', -content => 'text/css' } ), |
|
127 | + $q->meta( { -http_equiv => 'Content-script-type', -content => 'text/javascript' } ), |
|
128 | + ], |
|
129 | + -style => [ { -src => $config->{ 'CSSFile' } }, ], |
|
130 | + ); |
|
131 | + $ret .= $q->h1( $q->a( { -href => $q->url }, $cgi_name ) ); |
|
132 | +# $ret .= $q->pre( YAML::Syck::Dump( $cookie ) ); |
|
133 | + return $ret; |
|
134 | +} |
|
135 | + |
|
136 | +sub makeFooter |
|
137 | +{ |
|
138 | + my $ret = ''; |
|
139 | + $ret .= $q->end_html . "\n"; |
|
140 | + return $ret; |
|
141 | +} |
|
142 | + |
|
143 | +sub makeForm |
|
144 | +{ |
|
145 | + my $ret = ''; |
|
146 | + $ret .= $q->start_multipart_form( -action => $q->url, ); |
|
147 | + $ret .= $q->table( |
|
148 | + $q->Tr( |
|
149 | + $q->th( '名前' ), |
|
150 | + $q->td( $q->textfield( |
|
151 | + -name => 'UserName', |
|
152 | + -default => $user_name, |
|
153 | + -size => 60, |
|
154 | + -override => 1, |
|
155 | + ) ), |
|
156 | + ), |
|
157 | + $q->Tr( |
|
158 | + $q->th( 'Email' ), |
|
159 | + $q->td( $q->textfield( |
|
160 | + -name => 'UserEmail', |
|
161 | + -default => $user_email, |
|
162 | + -size => 60, |
|
163 | + -override => 1, |
|
164 | + ) ), |
|
165 | + ), |
|
166 | + $q->Tr( |
|
167 | + $q->th( '添付ファイル' ), |
|
168 | + $q->td( $q->filefield( |
|
169 | + -name => 'Attachment', |
|
170 | + -default => '', |
|
171 | + -size => 60, |
|
172 | + -override => 1, |
|
173 | + ) ), |
|
174 | + ), |
|
175 | + $q->Tr( |
|
176 | + $q->th( 'コメント' ), |
|
177 | + $q->td( $q->textarea( |
|
178 | + -name => 'Comment', |
|
179 | + -default => '', |
|
180 | + -columns => 60, |
|
181 | + -rows => 5, |
|
182 | + -override => 1, |
|
183 | + ) ), |
|
184 | + ), |
|
185 | + $q->Tr( |
|
186 | + $q->th( 'アクセス元' ), |
|
187 | + $q->td( "$remote_ip; $remote_name" ), |
|
188 | + ), |
|
189 | + $q->Tr( $q->td( |
|
190 | + { -colspan => 2, -align => 'center', }, |
|
191 | + $q->submit( -name => 'Submit', -value => 'Submit' ), |
|
192 | + ), ), |
|
193 | + ); |
|
194 | + $ret .= $q->hidden( -name => 'Command', -default => 'doPost', -override => 1 ); |
|
195 | + $ret .= $q->end_multipart_form; |
|
196 | + return $ret; |
|
197 | +} |
|
198 | + |
|
199 | +sub showPostedInfo |
|
200 | +{ |
|
201 | + my $ret = ''; |
|
202 | + $ret .= $q->table( |
|
203 | + $q->Tr( $q->th( '名前' ), $q->td( $user_name ), ), |
|
204 | + $q->Tr( $q->th( 'Email' ), $q->td( $user_email ), ), |
|
205 | + $q->Tr( $q->th( 'コメント' ), $q->td( $comment ), ), |
|
206 | + $q->Tr( $q->th( 'アクセス元' ), $q->td( "$remote_ip; $remote_name" ), ), |
|
207 | + $q->Tr( $q->th( 'ファイル名' ), $q->td( $file_name ), ), |
|
208 | + $q->Tr( $q->th( 'ファイルタイプ' ), $q->td( $file_type ), ), |
|
209 | + $q->Tr( $q->th( 'ファイルサイズ' ), $q->td( length( $file_body ), ), ), |
|
210 | + $q->Tr( $q->th( 'Hex' ), $q->td( dumpStr( $file_body ) ), ), |
|
211 | + ); |
|
212 | + return $ret; |
|
213 | +} |
|
214 | + |
|
215 | +sub dumpStr |
|
216 | +{ |
|
217 | + my $dump_limit = 64; |
|
218 | + my $str = shift || ''; |
|
219 | + my $head = shift || $dump_limit; |
|
220 | + if ( $head > $dump_limit ){ |
|
221 | + $head = $dump_limit; |
|
222 | + } |
|
223 | + if ( $head > length( $str ) ){ |
|
224 | + $head = length( $str ); |
|
225 | + } |
|
226 | + $str = substr( $str, 0, $head ); |
|
227 | + my $ret = ''; |
|
228 | + my @buffer = (); |
|
229 | + for( my $i=0; $i<$head; $i+=16 ){ |
|
230 | + for( my $j=0; $j<16 && ( $i + $j < $head ); ++$j ){ |
|
231 | + push( @buffer, unpack( "H*", substr( $str, $i + $j, 1 ) ) ); |
|
232 | + } |
|
233 | + push( @buffer, $br ); |
|
234 | + } |
|
235 | + $ret = join( " ", @buffer ); |
|
236 | + return $ret; |
|
237 | +} |
|
238 | + |
|
239 | +sub sendMail |
|
240 | +{ |
|
241 | + my $body = "名前:\n${user_name}\n\nEmail:\n${user_email}\n\nコメント:\n${comment}\n\n" |
|
242 | + . "アクセス元:\n${remote_ip}; ${remote_name}\n\n"; |
|
243 | + my $email = Email::MIME->create( |
|
244 | + attributes => { |
|
245 | + content_type => 'text/plain', |
|
246 | + charset => 'UTF-8', |
|
247 | + encoding => '8bit', |
|
248 | + #encoding => 'base64', |
|
249 | + }, |
|
250 | + header_str => [ |
|
251 | + From => $config->{ 'FromAddress' }, |
|
252 | + To => join( ", ", $config->{ 'ToAddress' }, $user_email, ) , |
|
253 | + Subject => $config->{ 'MailTitle' }, |
|
254 | + ], |
|
255 | + parts => [ |
|
256 | + Email::MIME->create( |
|
257 | + attributes => { |
|
258 | + content_type => 'text/plain', |
|
259 | + charset => 'UTF-8', |
|
260 | + #encoding => '8bit', |
|
261 | + encoding => 'base64', |
|
262 | + }, |
|
263 | + body => encode( $charset_input, $body ), |
|
264 | + ), |
|
265 | + Email::MIME->create( |
|
266 | + attributes => { |
|
267 | + content_type => $file_type, |
|
268 | + name => encode( 'MIME-Header', $file_name ), |
|
269 | + filename => encode( 'MIME-Header', $file_name ), |
|
270 | + encoding => 'base64', |
|
271 | + disposition => 'attachment', |
|
272 | + }, |
|
273 | + body => $file_body, |
|
274 | + ), |
|
275 | + ], |
|
276 | + ); |
|
277 | + |
|
278 | + return sendmail($email); |
|
279 | +} |
|
280 | + |
|
281 | +sub getHostName |
|
282 | +{ |
|
283 | + my $ip_address = shift || ''; |
|
284 | + my $ret = ''; |
|
285 | + |
|
286 | + my $resolver = Net::DNS::Resolver->new; |
|
287 | + if ( my $ans = $resolver->query( $ip_address ) ){ |
|
288 | + for my $rr ( $ans->answer ){ |
|
289 | + #print $rr->string, "\n"; |
|
290 | + if ( $rr->type eq 'PTR' ){ |
|
291 | + $ret = $rr->ptrdname; |
|
292 | + last; |
|
293 | + } |
|
294 | + } |
|
295 | + } |
|
296 | + |
|
297 | + return $ret; |
|
298 | +} |
|
299 | + |
|
300 | +# EOF |
|
301 | +``` |
|
302 | + |
|
303 | +## config.yaml |
|
304 | +``` |
|
305 | +# MailForm 設定 |
|
306 | +FromAddress: '"メールフォーム" <MailForm@example.com>' |
|
307 | +ToAddress: '"YourAddress" <YourAddress@example.com>' |
|
308 | +MailTitle: "レポート" |
|
309 | +CSSFile: "/take.css" |
|
310 | +``` |
|
311 | + |
|
312 | +# mod_security |
|
313 | +- セッション使わず、クッキーの中にユーザ名と Email がそのまま入っていて、mod_security の crs でエラーになる。 |
|
314 | +- 該当するルール |
|
315 | + - file: modsecurity_crs_41_sql_injection_attacks.conf |
|
316 | + - id: 960024, 981172, 981243, 981245, 981246, 981257 |
|
317 | + |
|
318 | +# リンク |
|
319 | +- [CPAN:Email-Sender](http://search.cpan.org/dist/Email-Sender) |
|
320 | + - [CPAN:Email-Sender/lib/Email/Sender/Manual/QuickStart.pm](http://search.cpan.org/dist/Email-Sender/lib/Email/Sender/Manual/QuickStart.pm) |
|
321 | +- [CPAN:Email-Address](http://search.cpan.org/dist/Email-Address) |
|
322 | +- [CPAN:Email-MIME](http://search.cpan.org/dist/Email-MIME) |
|
323 | +- [CPAN:CGI](http://search.cpan.org/dist/CGI) |
|
324 | + - [CPAN:CGI/lib/CGI.pm](http://search.cpan.org/dist/CGI/lib/CGI.pm) |
|
325 | + - [CPAN:CGI/lib/CGI/Cookie.pm](http://search.cpan.org/dist/CGI/lib/CGI/Cookie.pm) |
|
326 | +- [CPAN:CGI-Session](http://search.cpan.org/dist/CGI-Session) |
|
327 | + - [CPAN:CGI-Session/lib/CGI/Session/Tutorial.pm](http://search.cpan.org/dist/CGI-Session/lib/CGI/Session/Tutorial.pm) |
|
328 | + |
|
329 | +- [モダンPerlの世界へようこそ … 技術評論社](http://gihyo.jp/dev/serial/01/modern-perl) |
|
330 | + - [第20回 Email::Sender:メールを送信する](http://gihyo.jp/dev/serial/01/modern-perl/0020) |
|
331 | + |
|
332 | +- [404 Blog Not Found](http://blog.livedoor.jp/dankogai/) |
|
333 | + - [ドコモもauはとりあえず"da..me."@を受け取れるようにしとくべし](http://blog.livedoor.jp/dankogai/archives/50954045.html) |
|
... | ... | \ No newline at end of file |
Perl/MatchList.md
... | ... | @@ -0,0 +1,79 @@ |
1 | +[[_TOC_]] |
|
2 | +---- |
|
3 | +# 概要 |
|
4 | +- 正規表現によるマッチ結果をリスト化する。 |
|
5 | +- リストコンテキストで /g を付けて評価する。 |
|
6 | + |
|
7 | +# ソース |
|
8 | +- [matchlist.zip](matchlist.zip) |
|
9 | +```perl |
|
10 | +# マッチ結果のリスト化 |
|
11 | +# リストコンテキストで /g を付けて評価する。 |
|
12 | + |
|
13 | +use strict; |
|
14 | +use warnings; |
|
15 | +use utf8; |
|
16 | +use Encode; |
|
17 | + |
|
18 | +#my $charsetConsole = 'UTF-8'; |
|
19 | +my $charsetConsole = 'CP932'; |
|
20 | +my $charsetFile = 'UTF-8'; |
|
21 | + |
|
22 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
23 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
24 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
25 | + |
|
26 | +# 次の文字列を「key=val」として分解する |
|
27 | +# key は空白を含みうる。val は空白を含まない。 |
|
28 | +# 「t u」はマッチしないので無視される |
|
29 | +my $line = "aa = bb cc dd= ee ff gg hh= ii jj kk = ll mm=nn o= p q r= s t u"; |
|
30 | +print "${line}\n\n"; |
|
31 | + |
|
32 | +# ペア単位でリスト化した後、key/valに分解。順序は保存される。 |
|
33 | +foreach my $pair ( $line =~ /[^=]*\S\s*=\s*\S+\s*/g ){ |
|
34 | + my( $key, $val ) = ( $pair =~ /^([^=]*\S)\s*=\s*(\S+)\s*$/ ); |
|
35 | + print "key:'${key}'\tval:'${val}'\n"; |
|
36 | +} |
|
37 | +print "\n"; |
|
38 | + |
|
39 | +# マッチ結果リストをハッシュとして受ける。順序は保存されない。 |
|
40 | +my %pairs = ( $line =~ /([^=]*\S)\s*=\s*(\S+)\s*/g ); |
|
41 | +foreach my $key ( keys( %pairs ) ){ |
|
42 | + print "key:'${key}'\tval:'${pairs{$key}}'\n"; |
|
43 | +} |
|
44 | + |
|
45 | +# EOF |
|
46 | +``` |
|
47 | + |
|
48 | +# 出力結果 |
|
49 | +``` |
|
50 | +aa = bb cc dd= ee ff gg hh= ii jj kk = ll mm=nn o= p q r= s t u |
|
51 | + |
|
52 | +key:'aa' val:'bb' |
|
53 | +key:'cc dd' val:'ee' |
|
54 | +key:'ff gg hh' val:'ii' |
|
55 | +key:'jj kk' val:'ll' |
|
56 | +key:'mm' val:'nn' |
|
57 | +key:'o' val:'p' |
|
58 | +key:'q r' val:'s' |
|
59 | + |
|
60 | +key:'jj kk' val:'ll' |
|
61 | +key:'mm' val:'nn' |
|
62 | +key:'q r' val:'s' |
|
63 | +key:'ff gg hh' val:'ii' |
|
64 | +key:'cc dd' val:'ee' |
|
65 | +key:'aa' val:'bb' |
|
66 | +key:'o' val:'p' |
|
67 | +``` |
|
68 | + |
|
69 | +# リンク |
|
70 | +- [[Perl/ApacheErrorLogFormatter]] |
|
71 | + |
|
72 | +- http://perldoc.jp/ |
|
73 | + - [Perl の正規表現のチュートリアル](http://perldoc.jp/docs/perl/5.14.1/perlretut.pod) |
|
74 | + |
|
75 | +- [Perl programming documentation](http://perldoc.perl.org/) |
|
76 | + - [perlrequick](http://perldoc.perl.org/perlrequick.html) |
|
77 | + |
|
78 | +- [DebugIto's](http://debugitos.main.jp/) |
|
79 | + - [一つの正規表現パターンで複数回マッチ](http://debugitos.main.jp/?Perl/Tips#y2638d73) |
|
... | ... | \ No newline at end of file |
Perl/MySQL-BIT.md
... | ... | @@ -0,0 +1,291 @@ |
1 | +# MySQL BIT型 |
|
2 | +[[_TOC_]] |
|
3 | + |
|
4 | +## 概要 |
|
5 | +- DBI から BIT 型にバインドする際には pack('C*',$x) してからバインドするべし。 |
|
6 | +- BIT は TINYINT として実装されている。 |
|
7 | +- 格納できる数値より大きな値を格納しようとした場合は全ビットが1になった値が格納される。 |
|
8 | + |
|
9 | +## ソース |
|
10 | +- [testBit.zip](testBit.zip) |
|
11 | + |
|
12 | +### testBit.pl |
|
13 | +```perl |
|
14 | +#!/usr/bin/perl |
|
15 | +# testBit.pl |
|
16 | +# MySQL の Bit 型の取り扱いテスト |
|
17 | + |
|
18 | +use strict; |
|
19 | +use warnings; |
|
20 | +use utf8; |
|
21 | +use Encode; |
|
22 | +use YAML::Syck; |
|
23 | +use JSON::Syck; |
|
24 | +use lib qw( /home/Shared/lib/ ); |
|
25 | +use DBIx::NamedParams; |
|
26 | + |
|
27 | +$YAML::Syck::ImplicitUnicode = 1; |
|
28 | +$YAML::Syck::ImplicitTyping = 1; |
|
29 | +$YAML::Syck::Headless = 1; |
|
30 | + |
|
31 | +my $charsetConsole = 'UTF-8'; |
|
32 | +#my $charsetConsole = 'CP932'; |
|
33 | +my $charsetFile = 'UTF-8'; |
|
34 | + |
|
35 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
36 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
37 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
38 | + |
|
39 | +my $config_file = 'config.yaml'; |
|
40 | + |
|
41 | +my $sql_insert = qq{ |
|
42 | + INSERT INTO |
|
43 | + `test_bit` |
|
44 | + ( `packtype`, `value`, `bit1`, `bit4`, `bit8`, `bit12`, `bit16` ) |
|
45 | + VALUES |
|
46 | + ( :packtype-VARCHAR, :value-VARCHAR, :bit1-BIT, :bit4-BIT, :bit8-BIT, :bit12-BIT, :bit16-BIT ); |
|
47 | +}; |
|
48 | +my $sql_select = qq{ |
|
49 | + SELECT `id`, `packtype`, `value`, `bit1`, `bit4`, `bit8`, `bit12`, `bit16` |
|
50 | + FROM `test_bit` |
|
51 | + ORDER BY `id` |
|
52 | +}; |
|
53 | + |
|
54 | +my @input_types = qw( N B C ); |
|
55 | +my @input_values = qw( |
|
56 | + 0 1 10 100 1000 10000 100000000 100000000000 1000000000000 10000000000000000 |
|
57 | + 01 001 0001 00001 000000001 000000000001 0000000000001 00000000000000001 |
|
58 | + 010 0010 00010 000010 0000000010 0000000000010 00000000000010 000000000000000010 |
|
59 | + 2 3 4 5 6 7 8 10 12 15 16 17 255 256 512 513 |
|
60 | +); |
|
61 | + |
|
62 | +my $config = YAML::Syck::LoadFile( $config_file ) |
|
63 | + or die( "$config_file: $!\n" ); |
|
64 | +foreach( keys( %{$config} ) ){ |
|
65 | + $config->{'DSN'} =~ s/_${_}_/$config->{$_}/; |
|
66 | +} |
|
67 | + |
|
68 | +my $dbh = DBI->connect( |
|
69 | + 'DBI:' . $config->{'DSN'}, |
|
70 | + $config->{'User'}, |
|
71 | + $config->{'Password'}, |
|
72 | + $config->{'Options'} |
|
73 | +) or die( "$DBI::errstr\n" ); |
|
74 | + |
|
75 | +my $sth_insert = $dbh->prepare_ex( $sql_insert ) or die( "$DBI::errstr\n" ); |
|
76 | +foreach my $type ( @input_types ){ |
|
77 | + foreach my $value ( @input_values ){ |
|
78 | + my $params = { packtype => $type, value => $value }; |
|
79 | + foreach my $bit ( qw( 1 4 8 12 16 ) ){ |
|
80 | + if ( $type eq 'B' ){ |
|
81 | + $params->{ "bit${bit}" } = pack( "B${bit}", $value ); |
|
82 | + } elsif( $type eq 'C' ){ |
|
83 | + $params->{ "bit${bit}" } = pack( 'C*', int2array( $value ) ); |
|
84 | + } else { |
|
85 | + $params->{ "bit${bit}" } = $value; |
|
86 | + } |
|
87 | + } |
|
88 | + $sth_insert->bind_param_ex( $params ); |
|
89 | + $sth_insert->execute() or die( "$DBI::errstr\n" ); |
|
90 | + } |
|
91 | +} |
|
92 | +$sth_insert->finish; |
|
93 | + |
|
94 | +my $sth_select = $dbh->prepare_ex( $sql_select ) or die( "$DBI::errstr\n" ); |
|
95 | +$sth_select->execute() or die( "$DBI::errstr\n" ); |
|
96 | +my @result = (); |
|
97 | +while( my $array_ref = $sth_select->fetchrow_arrayref ){ |
|
98 | + my @result2 = split( "\n", Dump( $array_ref ) ); |
|
99 | + push( @result, join( "\t", map{ /^\s*-\s*(.*)$/msx; $1; } @result2 ) ); |
|
100 | +} |
|
101 | +$sth_select->finish; |
|
102 | + |
|
103 | +$dbh->disconnect; |
|
104 | + |
|
105 | +print join( "\n", @result ) . "\n"; |
|
106 | + |
|
107 | +exit; |
|
108 | + |
|
109 | +sub int2array |
|
110 | +{ |
|
111 | + my $arg = shift || 0; |
|
112 | + my @ret = (); |
|
113 | + if ( !!$arg ){ |
|
114 | + while( !!$arg ){ |
|
115 | + my $m = $arg & 0xff; |
|
116 | + unshift( @ret, $m ); |
|
117 | + $arg >>= 8; |
|
118 | + } |
|
119 | + } else { |
|
120 | + @ret = ( 0 ); |
|
121 | + } |
|
122 | + return @ret; |
|
123 | +} |
|
124 | + |
|
125 | +# EOF |
|
126 | +``` |
|
127 | + |
|
128 | +## 結果 |
|
129 | + |
|
130 | +### 無変換 |
|
131 | +| id | Type | 値 | bit1 | bit4 | bit8 | bit12 | bit16 | |
|
132 | +| --- | --- | --- | --- | --- | --- | --- | --- | |
|
133 | +| 1 | 'N' | | "\x01" | "\x0F" | | "\00" | "\00" | |
|
134 | +| 2 | 'N' | 1 | "\x01" | "\x0F" | 1 | "\01" | "\01" | |
|
135 | +| 3 | 'N' | 10 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | 10 | |
|
136 | +| 4 | 'N' | 100 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
137 | +| 5 | 'N' | 1000 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
138 | +| 6 | 'N' | 10000 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
139 | +| 7 | 'N' | 100000000 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
140 | +| 8 | 'N' | '100000000000' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
141 | +| 9 | 'N' | '1000000000000' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
142 | +| 10 | 'N' | '10000000000000000' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
143 | +| 11 | 'N' | '01' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | '01' | |
|
144 | +| 12 | 'N' | '001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
145 | +| 13 | 'N' | '0001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
146 | +| 14 | 'N' | '00001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
147 | +| 15 | 'N' | '000000001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
148 | +| 16 | 'N' | '000000000001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
149 | +| 17 | 'N' | '0000000000001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
150 | +| 18 | 'N' | '00000000000000001' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
151 | +| 19 | 'N' | '010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
152 | +| 20 | 'N' | '0010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
153 | +| 21 | 'N' | '00010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
154 | +| 22 | 'N' | '000010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
155 | +| 23 | 'N' | '0000000010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
156 | +| 24 | 'N' | '0000000000010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
157 | +| 25 | 'N' | '00000000000010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
158 | +| 26 | 'N' | '000000000000000010' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
159 | +| 27 | 'N' | 2 | "\x01" | "\x0F" | 2 | "\02" | "\02" | |
|
160 | +| 28 | 'N' | 3 | "\x01" | "\x0F" | 3 | "\03" | "\03" | |
|
161 | +| 29 | 'N' | 4 | "\x01" | "\x0F" | 4 | "\04" | "\04" | |
|
162 | +| 30 | 'N' | 5 | "\x01" | "\x0F" | 5 | "\05" | "\05" | |
|
163 | +| 31 | 'N' | 6 | "\x01" | "\x0F" | 6 | "\06" | "\06" | |
|
164 | +| 32 | 'N' | 7 | "\x01" | "\x0F" | 7 | "\07" | "\07" | |
|
165 | +| 33 | 'N' | 8 | "\x01" | "\x0F" | 8 | "\08" | "\08" | |
|
166 | +| 34 | 'N' | 10 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | 10 | |
|
167 | +| 35 | 'N' | 12 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | 12 | |
|
168 | +| 36 | 'N' | 15 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | 15 | |
|
169 | +| 37 | 'N' | 16 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | 16 | |
|
170 | +| 38 | 'N' | 17 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | 17 | |
|
171 | +| 39 | 'N' | 255 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
172 | +| 40 | 'N' | 256 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
173 | +| 41 | 'N' | 512 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
174 | +| 42 | 'N' | 513 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
175 | + |
|
176 | +### pack('Bn',$x) |
|
177 | +| id | Type | 値 | bit1 | bit4 | bit8 | bit12 | bit16 | |
|
178 | +| --- | --- | --- | --- | --- | --- | --- | --- | |
|
179 | +| 43 | B | | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
180 | +| 44 | B | 1 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
181 | +| 45 | B | 10 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
182 | +| 46 | B | 100 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
183 | +| 47 | B | 1000 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
184 | +| 48 | B | 10000 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
185 | +| 49 | B | 100000000 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
186 | +| 50 | B | '100000000000' | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
187 | +| 51 | B | '1000000000000' | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
188 | +| 52 | B | '10000000000000000' | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
189 | +| 53 | B | '01' | "\0" | "\x0F" | "@" | "\x0F\xFF" | "@\0" | |
|
190 | +| 54 | B | '001' | "\0" | "\x0F" | " " | "\x0F\xFF" | " \0" | |
|
191 | +| 55 | B | '0001' | "\0" | "\x0F" | "\x10" | "\x0F\xFF" | "\x10\0" | |
|
192 | +| 56 | B | '00001' | "\0" | "\0" | "\b" | "\b\0" | "\b\0" | |
|
193 | +| 57 | B | '000000001' | "\0" | "\0" | "\0" | "\0\x80" | "\0\x80" | |
|
194 | +| 58 | B | '000000000001' | "\0" | "\0" | "\0" | "\0\x10" | "\0\x10" | |
|
195 | +| 59 | B | '0000000000001' | "\0" | "\0" | "\0" | "\0\0" | "\0\b" | |
|
196 | +| 60 | B | '00000000000000001' | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
197 | +| 61 | B | '010' | "\0" | "\x0F" | "@" | "\x0F\xFF" | "@\0" | |
|
198 | +| 62 | B | '0010' | "\0" | "\x0F" | " " | "\x0F\xFF" | " \0" | |
|
199 | +| 63 | B | '00010' | "\0" | "\x0F" | "\x10" | "\x0F\xFF" | "\x10\0" | |
|
200 | +| 64 | B | '000010' | "\0" | "\0" | "\b" | "\b\0" | "\b\0" | |
|
201 | +| 65 | B | '0000000010' | "\0" | "\0" | "\0" | "\0\x80" | "\0\x80" | |
|
202 | +| 66 | B | '0000000000010' | "\0" | "\0" | "\0" | "\0\x10" | "\0\x10" | |
|
203 | +| 67 | B | '00000000000010' | "\0" | "\0" | "\0" | "\0\0" | "\0\b" | |
|
204 | +| 68 | B | '000000000000000010' | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
205 | +| 69 | B | 2 | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
206 | +| 70 | B | 3 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
207 | +| 71 | B | 4 | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
208 | +| 72 | B | 5 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
209 | +| 73 | B | 6 | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
210 | +| 74 | B | 7 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
211 | +| 75 | B | 8 | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
212 | +| 76 | B | 10 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
213 | +| 77 | B | 12 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
214 | +| 78 | B | 15 | "\x01" | "\x0F" | "\xC0" | "\x0F\xFF" | "\xC0\0" | |
|
215 | +| 79 | B | 16 | "\x01" | "\x0F" | "\x80" | "\x0F\xFF" | "\x80\0" | |
|
216 | +| 80 | B | 17 | "\x01" | "\x0F" | "\xC0" | "\x0F\xFF" | "\xC0\0" | |
|
217 | +| 81 | B | 255 | "\0" | "\x0F" | "`" | "\x0F\xFF" | "`\0" | |
|
218 | +| 82 | B | 256 | "\0" | "\x0F" | "@" | "\x0F\xFF" | "@\0" | |
|
219 | +| 83 | B | 512 | "\x01" | "\x0F" | "\xC0" | "\x0F\xFF" | "\xC0\0" | |
|
220 | +| 84 | B | 513 | "\x01" | "\x0F" | "\xE0" | "\x0F\xFF" | "\xE0\0" | |
|
221 | + |
|
222 | +### pack('C*',$x) |
|
223 | +| id | Type | 値 | bit1 | bit4 | bit8 | bit12 | bit16 | |
|
224 | +| --- | --- | --- | --- | --- | --- | --- | --- | |
|
225 | +| 85 | C | | "\0" | "\0" | "\0" | "\0\0" | "\0\0" | |
|
226 | +| 86 | C | 1 | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
227 | +| 87 | C | 10 | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
228 | +| 88 | C | 100 | "\x01" | "\x0F" | d | "\0d" | "\0d" | |
|
229 | +| 89 | C | 1000 | "\x01" | "\x0F" | "\xFF" | "\x03\xE8" | "\x03\xE8" | |
|
230 | +| 90 | C | 10000 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "'\x10" | |
|
231 | +| 91 | C | 100000000 | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
232 | +| 92 | C | '100000000000' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
233 | +| 93 | C | '1000000000000' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
234 | +| 94 | C | '10000000000000000' | "\x01" | "\x0F" | "\xFF" | "\x0F\xFF" | "\xFF\xFF" | |
|
235 | +| 95 | C | '01' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
236 | +| 96 | C | '001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
237 | +| 97 | C | '0001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
238 | +| 98 | C | '00001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
239 | +| 99 | C | '000000001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
240 | +| 100 | C | '000000000001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
241 | +| 101 | C | '0000000000001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
242 | +| 102 | C | '00000000000000001' | "\x01" | "\x01" | "\x01" | "\0\x01" | "\0\x01" | |
|
243 | +| 103 | C | '010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
244 | +| 104 | C | '0010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
245 | +| 105 | C | '00010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
246 | +| 106 | C | '000010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
247 | +| 107 | C | '0000000010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
248 | +| 108 | C | '0000000000010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
249 | +| 109 | C | '00000000000010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
250 | +| 110 | C | '000000000000000010' | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
251 | +| 111 | C | 2 | "\x01" | "\x02" | "\x02" | "\0\x02" | "\0\x02" | |
|
252 | +| 112 | C | 3 | "\x01" | "\x03" | "\x03" | "\0\x03" | "\0\x03" | |
|
253 | +| 113 | C | 4 | "\x01" | "\x04" | "\x04" | "\0\x04" | "\0\x04" | |
|
254 | +| 114 | C | 5 | "\x01" | "\x05" | "\x05" | "\0\x05" | "\0\x05" | |
|
255 | +| 115 | C | 6 | "\x01" | "\x06" | "\x06" | "\0\x06" | "\0\x06" | |
|
256 | +| 116 | C | 7 | "\x01" | "\a" | "\a" | "\0\a" | "\0\a" | |
|
257 | +| 117 | C | 8 | "\x01" | "\b" | "\b" | "\0\b" | "\0\b" | |
|
258 | +| 118 | C | 10 | "\x01" | "\n" | "\n" | "\0\n" | "\0\n" | |
|
259 | +| 119 | C | 12 | "\x01" | "\f" | "\f" | "\0\f" | "\0\f" | |
|
260 | +| 120 | C | 15 | "\x01" | "\x0F" | "\x0F" | "\0\x0F" | "\0\x0F" | |
|
261 | +| 121 | C | 16 | "\x01" | "\x0F" | "\x10" | "\0\x10" | "\0\x10" | |
|
262 | +| 122 | C | 17 | "\x01" | "\x0F" | "\x11" | "\0\x11" | "\0\x11" | |
|
263 | +| 123 | C | 255 | "\x01" | "\x0F" | "\xFF" | "\0\xFF" | "\0\xFF" | |
|
264 | +| 124 | C | 256 | "\x01" | "\x0F" | "\xFF" | "\x01\0" | "\x01\0" | |
|
265 | +| 125 | C | 512 | "\x01" | "\x0F" | "\xFF" | "\x02\0" | "\x02\0" | |
|
266 | +| 126 | C | 513 | "\x01" | "\x0F" | "\xFF" | "\x02\x01" | "\x02\x01" | |
|
267 | + |
|
268 | +## テーブル |
|
269 | +```sql |
|
270 | +CREATE TABLE IF NOT EXISTS `test_bit` ( |
|
271 | + `id` int(11) NOT NULL AUTO_INCREMENT, |
|
272 | + `packtype` varchar(1) DEFAULT NULL, |
|
273 | + `value` varchar(20) DEFAULT NULL, |
|
274 | + `bit1` bit(1) DEFAULT NULL, |
|
275 | + `bit4` bit(4) DEFAULT NULL, |
|
276 | + `bit8` bit(8) DEFAULT NULL, |
|
277 | + `bit12` bit(12) DEFAULT NULL, |
|
278 | + `bit16` bit(16) DEFAULT NULL, |
|
279 | + PRIMARY KEY (`id`) |
|
280 | +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; |
|
281 | + |
|
282 | +DELETE FROM `test_bit` WHERE 1; |
|
283 | +ALTER TABLE `test_bit` AUTO_INCREMENT = 1; |
|
284 | +``` |
|
285 | + |
|
286 | +## リンク |
|
287 | +- Perl/packBit |
|
288 | +- MySQL |
|
289 | + |
|
290 | +- [PerlMonks - The Monastery Gates](http://www.perlmonks.org/) |
|
291 | + - [Handle MySQL BIT data type in Perl](http://www.perlmonks.org/?node_id=504470) |
|
... | ... | \ No newline at end of file |
Perl/NetWatcher.md
... | ... | @@ -0,0 +1,547 @@ |
1 | +[[_TOC_]] |
|
2 | + |
|
3 | +# 概要 |
|
4 | +- ネットワーク上のサーバの ping による死活監視および WakeOnLan によるリモート起動を行う。 |
|
5 | +- 監視するのはスクリプトを呼び出した時1回だけで履歴は取らない。 |
|
6 | +- 再度監視したい場合はタイトルがリンクになっているので、そこをクリックする。 |
|
7 | +- Windows/IIS 版を追加。(2012/03/28) |
|
8 | +- [CPAN:Doxygen-Filter-Perl](http://search.cpan.org/dist/Doxygen-Filter-Perl) 用タグの書き方が間違っていたのを訂正。(2012/03/28) |
|
9 | +- Linux/Apache 版で<form>が閉じていなかったのを修正。(2012/03/28) |
|
10 | +- 関数内で print するのを止め、HTML文字列を返すように変更。(2012/03/29) |
|
11 | +- NIC が2枚以上ある場合に対応。「/」で連結して書く。(2012/05/30) |
|
12 | +- Name の先頭に「#」が付いている行はコメントとして無視される。(2012/06/04) |
|
13 | + |
|
14 | +# ソース |
|
15 | +- [NetWatcher.zip](NetWatcher.zip) |
|
16 | + |
|
17 | +## index.cgi (Linux/Apache) |
|
18 | +```perl |
|
19 | +#!/usr/bin/perl |
|
20 | +## @mainpage NetWatcher |
|
21 | +# サーバの監視およびリモート起動 |
|
22 | + |
|
23 | +use strict; |
|
24 | +use warnings; |
|
25 | +use utf8; |
|
26 | +use Encode; |
|
27 | +use YAML::Syck; |
|
28 | +use CGI::Pretty qw( -no_xhtml *table ); # //HTML 4.01 Transitional//EN |
|
29 | +use Text::xSV::Slurp qw( xsv_slurp ); |
|
30 | +use Net::Ping::External qw( ping ); |
|
31 | +use Net::Wake; |
|
32 | +use Parallel::ForkManager; |
|
33 | +use IPC::Shareable; |
|
34 | + |
|
35 | +$YAML::Syck::ImplicitUnicode = 1; |
|
36 | + |
|
37 | +#my $charsetConsole = 'CP932'; |
|
38 | +my $charsetConsole = 'UTF-8'; |
|
39 | +my $charsetFile = 'UTF-8'; |
|
40 | + |
|
41 | +binmode( STDIN, ":encoding($charsetConsole)" ); |
|
42 | +binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
43 | +binmode( STDERR, ":encoding($charsetConsole)" ); |
|
44 | + |
|
45 | +my $cginame = 'NetWatcher'; ##< CGI名 |
|
46 | +my $cookiename = 'NWCookie'; ##< 現在は使用していない |
|
47 | +my $configfile = './conf/config.txt'; ##< 設定ファイル |
|
48 | +my $csvoption = { sep_char => "\t" }; ##< 設定ファイルを読み込むためのオプション |
|
49 | +my $maxchildren = 10; ##< 子プロセスの最大数 |
|
50 | +my $markignore = '#'; ##< 行頭がこの文字列で始まっている行は無視する。 |
|
51 | + |
|
52 | +my @Targets = readXSV( $configfile, $csvoption ); |
|
53 | +my %Targets = map{ $_->{'Name'} => $_; } @Targets; |
|
54 | + |
|
55 | +#print Dump( \%Targets ) . "\n"; |
|
56 | +#exit; |
|
57 | + |
|
58 | +my %results = pingTargets( \@Targets ); |
|
59 | + |
|
60 | +my $q = new CGI; |
|
61 | +$q->charset( $charsetFile ); |
|
62 | +my $scripturl = $q->url( ); |
|
63 | + |
|
64 | +my @paramnames = $q->param(); |
|
65 | + |
|
66 | +printHeader(); |
|
67 | + |
|
68 | +if ( @paramnames ){ |
|
69 | + action(); |
|
70 | +} |
|
71 | +printForm(); |
|
72 | + |
|
73 | +printFooter(); |
|
74 | + |
|
75 | +exit; |
|
76 | + |
|
77 | +## @function readXSV( $fname, %$opt ) |
|
78 | +# CSV(TSV)ファイルを読み込んでヘッダ行をキーとしたハッシュの配列を返す。 |
|
79 | +# @param fname [in] ファイル名 |
|
80 | +# @param opt [in] Text::CSV_XS に渡されるオプション |
|
81 | +# @return CSVを配列化したもの |
|
82 | +sub readXSV |
|
83 | +{ |
|
84 | + my( $fname, $opt ) = @_; |
|
85 | + $opt = { binary => 1, %{$opt} }; |
|
86 | + open( my $fhin, "<:encoding($charsetFile)", encode( $charsetConsole, $fname ) ) |
|
87 | + or die( "$fname: $!" ); |
|
88 | + my @body = <$fhin>; |
|
89 | + close( $fhin ); |
|
90 | + my $ret = xsv_slurp( |
|
91 | + string => join( "", @body ), |
|
92 | + text_csv => $opt, |
|
93 | + ); |
|
94 | + return ( ref( $ret ) eq 'ARRAY' ) |
|
95 | + ? @{ $ret } |
|
96 | + : $ret ; |
|
97 | +} |
|
98 | + |
|
99 | +## @function pingTargets( @$targets_ref ) |
|
100 | +# ターゲット情報に従い、各ターゲット宛に ping を打ち、結果をハッシュにして返す。 |
|
101 | +# @param targets_ref [in] ターゲット情報の配列のリファレンス |
|
102 | +# @return ping 結果のハッシュ |
|
103 | +sub pingTargets |
|
104 | +{ |
|
105 | + my( $targets_ref ) = @_; |
|
106 | + |
|
107 | + my $handle = tie my %results, 'IPC::Shareable', undef, { destroy => 1 }; |
|
108 | + %results = (); |
|
109 | + |
|
110 | + my $pm = Parallel::ForkManager->new( $maxchildren ); |
|
111 | + |
|
112 | +# $pm->run_on_start( |
|
113 | +# sub { |
|
114 | +# my( $pid, $ident ) = @_; |
|
115 | +# print "** $ident started, pid: $pid\n"; |
|
116 | +# } |
|
117 | +# ); |
|
118 | + |
|
119 | + foreach my $target ( @{$targets_ref} ){ |
|
120 | + my $name = $target->{ 'Name' } || ''; |
|
121 | + if ( substr( $name, 0, length($markignore) ) eq $markignore ){ |
|
122 | + next; |
|
123 | + } |
|
124 | + my $ip = $target->{ 'IP' } || ''; |
|
125 | + $pm->start( $name ) and next; |
|
126 | + my $status = ping( host => $ip, timeout => 1 ); |
|
127 | + $handle->shlock; |
|
128 | + $results{ $name } = $status; |
|
129 | + $handle->shunlock; |
|
130 | + $pm->finish( $name ); |
|
131 | + } |
|
132 | + $pm->wait_all_children; |
|
133 | + |
|
134 | + my %ret = %results; |
|
135 | + $handle->remove(); |
|
136 | + |
|
137 | + return %ret; |
|
138 | +} |
|
139 | + |
|
140 | +## @function printHeader() |
|
141 | +# HTTP ヘッダおよび HTML ヘッダを出力する。 |
|
142 | +sub printHeader |
|
143 | +{ |
|
144 | + my $cookieval = decode( 'utf8', |
|
145 | + $q->cookie( encode( 'utf8', $cookiename ) ) || '' |
|
146 | + ); |
|
147 | +# $cookieval .= 'あ'; |
|
148 | + my $cookie = $q->cookie( |
|
149 | + '-name' => encode( 'utf8', $cookiename ), |
|
150 | + '-value' => encode( 'utf8', $cookieval ), |
|
151 | + ); |
|
152 | + print $q->header( '-cookie' => [ $cookie ] ); |
|
153 | + print $q->start_html( |
|
154 | + '-title' => $cginame, |
|
155 | + '-lang' => 'ja-JP', |
|
156 | + '-head' => [ |
|
157 | + $q->meta( { '-http_equiv' => 'Content-style-type', '-content' => 'text/css' } ), |
|
158 | + $q->meta( { '-http_equiv' => 'Content-script-type', '-content' => 'text/javascript' } ), |
|
159 | + ], |
|
160 | + '-style' => [ { 'src' => 'NetWatcher.css' }, ], |
|
161 | + ); |
|
162 | + print $q->h1( $q->a( { -href => $scripturl }, $cginame ) ); |
|
163 | +} |
|
164 | + |
|
165 | +## @function printFooter() |
|
166 | +# HTML フッタを出力する。 |
|
167 | +sub printFooter |
|
168 | +{ |
|
169 | + print $q->end_html . "\n"; |
|
170 | +} |
|
171 | + |
|
172 | +## @function action() |
|
173 | +# フォームから送信されたコマンドを処理する。 |
|
174 | +sub action |
|
175 | +{ |
|
176 | + print $q->h2( 'Command' ); |
|
177 | + print $q->start_table( { '-summary' => 'Servers', '-border' => 1 } ); |
|
178 | + foreach my $key ( @paramnames ){ |
|
179 | + print $q->Tr( |
|
180 | + { -class => 'even' }, |
|
181 | + $q->th( { -class => 'title' }, $key ), $q->td( $q->param( $key ) ) |
|
182 | + ); |
|
183 | + } |
|
184 | + print $q->end_table(); |
|
185 | + my $target = $q->param( 'Wake' ) || ''; |
|
186 | + if ( $target && $Targets{$target} ){ |
|
187 | + foreach my $mac ( split( /\//, $Targets{$target}{'MAC'} ) ){ |
|
188 | + Net::Wake::by_udp( undef, $mac ); |
|
189 | + } |
|
190 | + } |
|
191 | +} |
|
192 | + |
|
193 | +## @function printForm() |
|
194 | +# フォームを出力する。 |
|
195 | +sub printForm |
|
196 | +{ |
|
197 | + print $q->h2( 'ステータス' ); |
|
198 | + print $q->start_form( |
|
199 | + '-action' => $scripturl, |
|
200 | + '-enctype' => ( 'multipart/form-data' ), |
|
201 | + ); |
|
202 | + print $q->start_table( { '-summary' => 'Statuses', '-border' => 1 } ); |
|
203 | + print $q->Tr( $q->th( { -class => 'title' }, [ 'Name', 'Type', 'IP', 'Status', 'Wake', '備考' ] ) ); |
|
204 | + for( my $i=0; $i<@Targets; ++$i ){ |
|
205 | + my $name = $Targets[ $i ]{'Name'} || ''; |
|
206 | + if ( substr( $name, 0, length($markignore) ) eq $markignore ){ |
|
207 | + next; |
|
208 | + } |
|
209 | + my $type = $Targets[ $i ]{'Type'} || ''; |
|
210 | + my $ip = $Targets[ $i ]{'IP'} || ''; |
|
211 | + my $status = ( $results{ $name } ) |
|
212 | + ? $q->td( { -class => 'state_up' }, 'Up' ) |
|
213 | + : $q->td( { -class => 'state_down' }, 'Down' ); |
|
214 | + my $comment = $Targets[ $i ]{'Comment'} || ''; |
|
215 | + print $q->Tr( |
|
216 | + { -class => ( $i % 2 ) ? 'odd' : 'even' }, |
|
217 | + $q->th( $name ), |
|
218 | + $q->td( [ $type, $ip ] ), |
|
219 | + $status, |
|
220 | + $q->td( [ $q->submit( -name=>'Wake', -value=>$name ), $comment, ] ), |
|
221 | + ); |
|
222 | + } |
|
223 | + print $q->end_table(); |
|
224 | + $q->end_form; |
|
225 | +} |
|
226 | + |
|
227 | +# EOF |
|
228 | +``` |
|
229 | + |
|
230 | +## index_IIS.cgi (Windows/IIS) |
|
231 | +```perl |
|
232 | +#!/usr/bin/perl |
|
233 | +# NetWatcher (IIS用) |
|
234 | +# サーバの監視およびリモート起動 |
|
235 | + |
|
236 | +use strict; |
|
237 | +use warnings; |
|
238 | +use utf8; |
|
239 | +use Encode; |
|
240 | +use YAML::Syck; |
|
241 | +use CGI::Pretty qw( -no_xhtml *table ); # //HTML 4.01 Transitional//EN |
|
242 | +use Text::xSV::Slurp qw( xsv_slurp ); |
|
243 | +use Net::Ping::External qw( ping ); |
|
244 | +use Net::Wake; |
|
245 | +use threads; |
|
246 | +use threads::shared; |
|
247 | + |
|
248 | +$YAML::Syck::ImplicitUnicode = 1; |
|
249 | + |
|
250 | +#my $charsetConsole = 'CP932'; |
|
251 | +my $charsetConsole = 'UTF-8'; |
|
252 | +my $charsetFile = 'UTF-8'; |
|
253 | + |
|
254 | +# Encode モジュールは Thread Safe ではない。 |
|
255 | +# http://search.cpan.org/dist/Encode/encoding.pm |
|
256 | +#binmode( STDIN, ":encoding($charsetConsole)" ); |
|
257 | +#binmode( STDOUT, ":encoding($charsetConsole)" ); |
|
258 | +#binmode( STDERR, ":encoding($charsetConsole)" ); |
|
259 | + |
|
260 | +my $encoder = find_encoding( $charsetConsole ); |
|
261 | + |
|
262 | +my $cginame = 'NetWatcher'; |
|
263 | +my $cookiename = 'NWCookie'; ##< 現在は使用していない |
|
264 | +my $configfile = './conf/config.txt'; |
|
265 | +my $csvoption = { sep_char => "\t" }; |
|
266 | +my $markignore = '#'; ##< 行頭がこの文字列で始まっている行は無視する。 |
|
267 | + |
|
268 | +my @Targets = readXSV( $configfile, $csvoption ); |
|
269 | +my %Targets = map{ $_->{'Name'} => $_; } @Targets; |
|
270 | + |
|
271 | +#print $encoder->encode( Dump( \%Targets ) . "\n" ); |
|
272 | +#exit; |
|
273 | + |
|
274 | +my %results = pingTargets( \@Targets ); |
|
275 | + |
|
276 | +my $q = new CGI; |
|
277 | +$q->charset( $charsetConsole ); |
|
278 | +my $scripturl = $q->url( -path_info=>1 ); |
|
279 | + |
|
280 | +my @paramnames = $q->param(); |
|
281 | + |
|
282 | +printHeader(); |
|
283 | + |
|
284 | +if ( @paramnames ){ |
|
285 | + action(); |
|
286 | +} |
|
287 | +printForm(); |
|
288 | + |
|
289 | +printFooter(); |
|
290 | + |
|
291 | +exit; |
|
292 | + |
|
293 | +## @function readXSV( $fname, %$opt ) |
|
294 | +# CSV(TSV)ファイルを読み込んでヘッダ行をキーとしたハッシュの配列を返す。 |
|
295 | +# @param fname [in] ファイル名 |
|
296 | +# @param opt [in] Text::CSV_XS に渡されるオプション |
|
297 | +# @return CSVを配列化したもの |
|
298 | +sub readXSV |
|
299 | +{ |
|
300 | + my( $fname, $opt ) = @_; |
|
301 | + $opt = { binary => 1, %{$opt} }; |
|
302 | + open( my $fhin, "<:encoding($charsetFile)", encode( $charsetConsole, $fname ) ) |
|
303 | + or die( "$fname: $!" ); |
|
304 | + my @body = <$fhin>; |
|
305 | + close( $fhin ); |
|
306 | + my $ret = xsv_slurp( |
|
307 | + string => join( "", @body ), |
|
308 | + text_csv => $opt, |
|
309 | + ); |
|
310 | + return ( ref( $ret ) eq 'ARRAY' ) |
|
311 | + ? @{ $ret } |
|
312 | + : $ret ; |
|
313 | +} |
|
314 | + |
|
315 | +## @function pingTargets( @%targetsref ) |
|
316 | +# ターゲット情報に従い、各ターゲット宛に ping を打ち、結果をハッシュにして返す。 |
|
317 | +# @param targets [in] ターゲット情報の配列 |
|
318 | +# @return ping 結果のハッシュ |
|
319 | +sub pingTargets |
|
320 | +{ |
|
321 | + my( $targets_ref ) = @_; |
|
322 | + |
|
323 | + my %results; |
|
324 | + my %threads; |
|
325 | + foreach my $target ( @{$targets_ref} ) { |
|
326 | + my $name = $target->{ 'Name' } || ''; |
|
327 | + if ( substr( $name, 0, length($markignore) ) eq $markignore ){ |
|
328 | + next; |
|
329 | + } |
|
330 | + my $ip = $target->{ 'IP' } || ''; |
|
331 | + $threads{ $name } = threads->new( |
|
332 | + sub { |
|
333 | + my( $ip ) = @_; |
|
334 | + return ping( host => $ip, timeout => 1 ); |
|
335 | + }, |
|
336 | + $ip |
|
337 | + ); |
|
338 | + } |
|
339 | + foreach my $t ( keys( %threads ) ){ |
|
340 | + $results{ $t } = $threads{ $t }->join(); |
|
341 | + } |
|
342 | + |
|
343 | + return %results; |
|
344 | +} |
|
345 | + |
|
346 | +## @function printHeader() |
|
347 | +# HTTP ヘッダおよび HTML ヘッダを出力する。 |
|
348 | +sub printHeader |
|
349 | +{ |
|
350 | + if ( defined( $ENV{PERLXS} ) && $ENV{PERLXS} eq 'PerlIS' ){ |
|
351 | + print $encoder->encode( "HTTP/1.0 200 OK\n" ); |
|
352 | + } |
|
353 | + |
|
354 | + my $cookieval = decode( 'utf8', |
|
355 | + $q->cookie( encode( 'utf8', $cookiename ) ) || '' |
|
356 | + ); |
|
357 | +# $cookieval .= 'あ'; |
|
358 | + my $cookie = $q->cookie( |
|
359 | + '-name' => encode( 'utf8', $cookiename ), |
|
360 | + '-value' => encode( 'utf8', $cookieval ), |
|
361 | + ); |
|
362 | + print $encoder->encode( $q->header( '-cookie' => [ $cookie ] ) ); |
|
363 | + print $encoder->encode( $q->start_html( |
|
364 | + '-title' => $cginame, |
|
365 | + '-lang' => 'ja-JP', |
|
366 | + '-head' => [ |
|
367 | + $q->meta( { '-http_equiv' => 'Content-style-type', '-content' => 'text/css' } ), |
|
368 | + $q->meta( { '-http_equiv' => 'Content-script-type', '-content' => 'text/javascript' } ), |
|
369 | + ], |
|
370 | + '-style' => [ { 'src' => 'NetWatcher.css' }, ], |
|
371 | + ) ); |
|
372 | + print $encoder->encode( $q->h1( $q->a( { -href => $scripturl }, $cginame ) ) ); |
|
373 | +} |
|
374 | + |
|
375 | +## @function printFooter() |
|
376 | +# HTML フッタを出力する。 |
|
377 | +sub printFooter |
|
378 | +{ |
|
379 | + print $encoder->encode( $q->end_html . "\n" ); |
|
380 | +} |
|
381 | + |
|
382 | +## @function action() |
|
383 | +# フォームから送信されたコマンドを処理する。 |
|
384 | +sub action |
|
385 | +{ |
|
386 | + print $encoder->encode( $q->h2( 'Command' ) ); |
|
387 | + print $encoder->encode( $q->start_table( { '-summary' => 'Servers', '-border' => 1 } ) ); |
|
388 | + foreach my $key ( @paramnames ){ |
|
389 | + print $encoder->encode( $q->Tr( |
|
390 | + { -class => 'even' }, |
|
391 | + $q->th( { -class => 'title' }, $key ), $q->td( $q->param( $key ) ) |
|
392 | + ) ); |
|
393 | + } |
|
394 | + print $encoder->encode( $q->end_table() ); |
|
395 | + my $target = $q->param( 'Wake' ) || ''; |
|
396 | + if ( $target && $Targets{$target} ){ |
|
397 | + foreach my $mac ( split( /\//, $Targets{$target}{'MAC'} ) ){ |
|
398 | + Net::Wake::by_udp( undef, $mac ); |
|
399 | + } |
|
400 | + } |
|
401 | +} |
|
402 | + |
|
403 | +## @function printForm() |
|
404 | +# フォームを出力する。 |
|
405 | +sub printForm |
|
406 | +{ |
|
407 | + print $encoder->encode( $q->h2( 'ステータス' ) ); |
|
408 | + print $encoder->encode( $q->start_form( |
|
409 | + '-action' => $scripturl, |
|
410 | + '-enctype' => ( 'multipart/form-data' ), |
|
411 | + ) ); |
|
412 | + print $encoder->encode( $q->start_table( { '-summary' => 'Statuses', '-border' => 1 } ) ); |
|
413 | + print $encoder->encode( $q->Tr( $q->th( { -class => 'title' }, [ 'Name', 'Type', 'IP', 'Status', 'Wake', '備考' ] ) ) ); |
|
414 | + for( my $i=0; $i<@Targets; ++$i ){ |
|
415 | + my $name = $Targets[ $i ]{'Name'} || ''; |
|
416 | + if ( substr( $name, 0, length($markignore) ) eq $markignore ){ |
|
417 | + next; |
|
418 | + } |
|
419 | + my $type = $Targets[ $i ]{'Type'} || ''; |
|
420 | + my $ip = $Targets[ $i ]{'IP'} || ''; |
|
421 | + my $status = ( $results{ $name } ) |
|
422 | + ? $q->td( { -class => 'state_up' }, 'Up' ) |
|
423 | + : $q->td( { -class => 'state_down' }, 'Down' ); |
|
424 | + my $comment = $Targets[ $i ]{'Comment'} || ''; |
|
425 | + print $encoder->encode( $q->Tr( |
|
426 | + { -class => ( $i % 2 ) ? 'odd' : 'even' }, |
|
427 | + $q->th( $name ), |
|
428 | + $q->td( [ $type, $ip ] ), |
|
429 | + $status, |
|
430 | + $q->td( [ $q->submit( -name=>'Wake', -value=>$name ), $comment, ] ), |
|
431 | + ) ); |
|
432 | + } |
|
433 | + print $encoder->encode( $q->end_table() ); |
|
434 | + print $encoder->encode( $q->end_form() ); |
|
435 | +} |
|
436 | + |
|
437 | +# EOF |
|
438 | +``` |
|
439 | + |
|
440 | +## config.txt |
|
441 | +- サーバ情報設定TSVファイル。 |
|
442 | +- MAC は WakeOnLan のパケットを送信する NIC の MAC アドレス。 |
|
443 | +- NIC が2枚以上ある場合は、「/」で連結して書く。 |
|
444 | +- Name の先頭に「#」が付いている行はコメントとして無視される。 |
|
445 | +``` |
|
446 | +"Name" "Type" "IP" "MAC" "Comment" |
|
447 | +"Srv01" "Win2003" "192.168.0.10" "XX:XX:XX:XX:XX:XX" "Web Hosting" |
|
448 | +"Srv02" "CentOS6" "192.168.0.11" "XX:XX:XX:XX:XX:XX/XX:XX:XX:XX:XX:XX" "Mail, MySQL" |
|
449 | +"#Srv03" "Win2008R2" "192.168.0.12" "XX:XX:XX:XX:XX:XX" "Streaming" |
|
450 | +"Srv04" "MacOSX 10.6" "192.168.0.13" "XX:XX:XX:XX:XX:XX" "FileSrv" |
|
451 | +``` |
|
452 | + |
|
453 | +## NetWatcher.conf |
|
454 | +- Apache 用設定ファイル。 |
|
455 | +- .htaccess でも代用可能。 |
|
456 | +```apache |
|
457 | +<Directory "/var/www/html/NetWatcher"> |
|
458 | + Options ExecCGI Indexes |
|
459 | + DirectoryIndex index.cgi |
|
460 | + Order allow,deny |
|
461 | + Allow from 127.0.0.1 |
|
462 | + Allow from 192.168.0.0/24 |
|
463 | + Allow from 10.8.0.0/24 |
|
464 | +</Directory> |
|
465 | + |
|
466 | +<Directory "/var/www/html/NetWatcher/conf"> |
|
467 | + Options None |
|
468 | + Order allow,deny |
|
469 | +</Directory> |
|
470 | +``` |
|
471 | + |
|
472 | +# システム設定 |
|
473 | + |
|
474 | +## パッケージ追加 |
|
475 | +- EPEL, RPMForge リポジトリを追加しておくこと。<br /> |
|
476 | +[[リポジトリ追加|Linux/Install/CentOS6#Repository]] |
|
477 | +``` |
|
478 | +# yum install perl-Net-Ping-External perl-Parallel-ForkManager perl-IPC-Shareable |
|
479 | +``` |
|
480 | + |
|
481 | +## SELinux設定 |
|
482 | +- audit.log を元にポリシーを作成しインストールする。<br /> |
|
483 | +[[ログ分析|Linux/SELinux#AnalyseLog]] |
|
484 | +``` |
|
485 | +# semodule -d mypol |
|
486 | +# setenforce 0 |
|
487 | +# service auditd rotate |
|
488 | +(NetWatcher実行) |
|
489 | +# setenforce 1 |
|
490 | +# grep "index.cgi\|ping" /var/log/audit/audit.log | audit2allow -M mypol_NetWatcher |
|
491 | +# semodule -i mypol_NetWatcher.pp |
|
492 | +``` |
|
493 | +- mypol_NetWatcher.te<br /> |
|
494 | +こんなポリシーができてるはず。 |
|
495 | +``` |
|
496 | +module mypol_NetWatcher 1.0; |
|
497 | + |
|
498 | +require { |
|
499 | + type httpd_sys_script_t; |
|
500 | + type tmpfs_t; |
|
501 | + class capability { setuid net_raw }; |
|
502 | + class sem { unix_read write unix_write read destroy create }; |
|
503 | + class shm { write associate read create unix_read getattr unix_write destroy }; |
|
504 | + class file { read write }; |
|
505 | + class rawip_socket { write getopt create read setopt }; |
|
506 | +} |
|
507 | + |
|
508 | +#============= httpd_sys_script_t ============== |
|
509 | +allow httpd_sys_script_t self:capability { setuid net_raw }; |
|
510 | +allow httpd_sys_script_t self:rawip_socket { write getopt create read setopt }; |
|
511 | +allow httpd_sys_script_t self:sem { unix_read write unix_write read destroy create }; |
|
512 | +allow httpd_sys_script_t self:shm { unix_read associate read create write getattr unix_write destroy }; |
|
513 | +allow httpd_sys_script_t tmpfs_t:file { read write }; |
|
514 | +``` |
|
515 | + |
|
516 | +- IIS の場合は、ping.exe の「プロパティ - セキュリティ」を開き、「インターネットゲストアカウント(IUSR_<マシン名>)」に「読み取りと実行」権限を付加する。 |
|
517 | + - [[PRB] [IIS 6.0] 外部アプリケーションを呼び出す CGI コードが失敗する](http://support.microsoft.com/kb/311481/) |
|
518 | + |
|
519 | +# リンク |
|
520 | +- [[Perl/CGI.pm]] |
|
521 | +- [[Perl/readXSV]] |
|
522 | + |
|
523 | +- [CPAN:Net-Ping-External](http://search.cpan.org/dist/Net-Ping-External) |
|
524 | +- [CPAN:Net-Arping](http://search.cpan.org/dist/Net-Arping) |
|
525 | +- [CPAN:Net-Wake](http://search.cpan.org/dist/Net-Wake) |
|
526 | +- [CPAN:Parallel-ForkManager](http://search.cpan.org/dist/Parallel-ForkManager) |
|
527 | +- [CPAN:IPC-Shareable](http://search.cpan.org/dist/IPC-Shareable) |
|
528 | +- [CPAN:threads](http://search.cpan.org/dist/threads) |
|
529 | +- [CPAN:threads-shared](http://search.cpan.org/dist/threads-shared) |
|
530 | +- [CPAN:Encode](http://search.cpan.org/dist/Encode) |
|
531 | + - [CPAN:Encode/encoding.pm](http://search.cpan.org/dist/Encode/encoding.pm)<br /> |
|
532 | +use encoding ... is not thread-safe. |
|
533 | + |
|
534 | +- [(Obsolete) Parallel::ForkManager + IPC::Shareable で複数のプロセスで変数を共有する - Yet Another Hackadelic](http://d.hatena.ne.jp/ZIGOROu/20090112/1231756261) |
|
535 | +- [パターン青の集い: memo::Perlによる複数並列処理プログラム](http://todayd308.blogspot.com/2009/10/memoperl.html) |
|
536 | + |