魔術師見習いのノート

プロフィール

魔術師見習い
Author魔術師見習い-_-.
Twitter魔術師見習い

コンピュータ関係のメモを主に書きます.

MENU

HTML 箇条書き(横書き)

投稿日:
タグ:

HTMLで,ニコニコ動画の上にある登録タグのようなものを書く(カンマやスペース等で区切って横に並べる)時,マークアップ言語的に<ul>を使って,見た目はCSSに任せるべきだと思い調べてみた.

見た目はこんな感じになる(Google Chrome19,Opera12, firefox12で確認).

  • hoge
  • fuga
  • piyo
  • hoge
  • fuga
  • piyo
以下が上のHTMLのCSSのサンプルコードである.
<style>
li {
  list-style:none;
  text-indent:0;
  margin:0;
  padding:0;
}
li:last-child {
  float:none;
}
li:not( :last-child ){
  float:left;
}
li:not( :last-child ):after{
  content:"・";
}
li:last-child:after{
  content:"";
}
</style>
contentの値を変えれば他の区切り記号になる.

また,Aタグを加えるとこういう見た目になる.

飛び先アドレスは全てgoogle

コンピュータ・ネットワーク(6) -アプリケーション層-

投稿日:
修正日:
タグ:

目次

アプリケーション層は、OSI参照モデルや5階層TCP/IPモデル、4階層TCP/IPモデルなどで最も上位の層である。

アプリケーション層
トランスポート層
ネットワーク層
データリンク層
物理層
本稿では、アプリケーション層のいくつかのプロトコルによって実装されるWebや電子メールについて紹介する。

ポート番号

5階層TCP/IPモデルでは、アプリケーション層の各プロトコルはトランスポート層で提供されるポートを利用する。そして、いくつかの有名なプロトコルでは、サーバで利用するポート番号がICANNによって標準化されている。また、それ以外の多くのプロトコルも使用するポート番号が明示されている。

ウェルノウンポート番号(well-known ports)0-1023ICANNで登録されているポート番号の範囲のうち有名なもの
登録済みポート番号1024-49151ICANNで登録されているポート番号の範囲
プライベート(ダイナミック)ポート番号49152-65535 ユーザやアプリケーションが自由に利用できるポート番号の範囲。多くの場合、クライアントアプリが必要に応じて動的に使用する。

ウェルノウンポート番号(0-1023)

TCP/UDPポート番号プロトコル名機能サーバ例クライアント例
TCP,UDP7ECHO 基本的にテスト用途で使用される。送られたデータをそのまま返す
TCP20FTPFile Transfer Protocolファイル送受信のためのプロトコル。データ転送用
  • Webブラウザ
  • ftp
TCP21ファイル送受信のためのプロトコル。制御用
TCP22SSHSecure SHell暗号や認証技術を用いた安全な通信やリモートログインのためのプロトコル。
  • OpenSSH Server
  • OpenSSH Client
TCP,UDP25SMTPSimple Mail Transfer Protocol電子メールの送受信に使用するプロトコル。
  • qmail
  • sendmail
  • thunderbird
  • Microsoft Outlook
TCP,UDP42WINSWindows Internet Naming Service Microsoft Windowsネットワーク上のコンピュータ名をIPアドレスに変換するためのプロトコル。宛先不明のため、クライアントはブロードキャストで問い合わせを行う。
TCP43WHOISドメイン名やIPアドレスなどの所有者情報を取得するためのプロトコル。
  • whois
TCP,UDP53DNSDomain Name System IPアドレスとドメイン名の対応情報を取得するためのプロトコル。
  • BIND
  • Djbdns
  • nslookup
  • dig
TCP,UDP80HTTPHyperText Transfer Protocol HTMLや画像、テキストなどの送受信のためのプロトコル。 Webサーバ
  • apache
  • IIS
Webブラウザ
  • Internet Explorer
  • Google Chrome
UDP123NTPNetwork Time Protocolマシンの時間を同期するためのプロトコル。
  • ntpdate
TCP443HTTP over SSLSSL通信を用いたSMTP
TCP465SMTP over SSLSSL通信を用いたSMTP

登録済みポート番号(1024-49151)

TCP/UDPポート番号プロトコル名機能サーバ例クライアント例
TCP,UDP1194OpenVPNオープンソースのVirtual Private Networkソフトウェアのためのプロトコル。
TCP,UDP1293IPSecInternet Protocol SecurityIPパケット単位でのデータ改ざん防止や秘匿機能を提供するためのプロトコル。
TCP,UDP3389RDPRemote Desktop ProtocolMicrosoftが開発しているリモートデスクトップサービスのためのプロトコル。
  • リモートデスクトップ接続
TCP,UDP5900VNCVirtual Network Computingリモートデスクトップ方式のためのプロトコル。
TCP6000X11ネットワーク経由でXを利用するためのプロトコル。
UDP6001
TCP8080HTTPの代替HTTPのプロキシサーバやキャッシュサーバなどに使用される。

プライベート(ダイナミック)ポート番号(49152-65535)

多くのプロトコルでは、クライアントアプリケーションが使用するポート番号は、プライベートポート番号の中で使われていないもの無作為に動的に使用する。例えば、WebブラウザでHTTP(80番ポート)のサイトにアクセスする際のパケット解析した結果の一部を示す。

user% tcpdump -n -X dst port 443 -i wlan0
06:29:52.791584 IP 192.168.1.14.60063 > 183.77.202.242.80: Flags
[S], seq 1904628341, win 14600, options [mss 1460,sackOK,TS val
104657554 ecr 0,nop,wscale 4], length 0
この解析後すぐにサーバとクライアントのTCPポートを確認すると、それぞれ次のような結果となる。
サーバ
uesr% telnet 183.77.202.242 80
Trying 183.77.202.242...
Connected to 183.77.202.242.
Escape character is '^]'.
クライアント
uesr% telnet localhost 60063
Trying ::1...
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
このようにクライアントのポートは、動的に使用される。

また、同じクライアントアプリを起動し直して再度同じページにアクセスしてもクライアントが使用するポート番号が同じであるとは限らない。

user% tcpdump -n -X dst port 443 -i wlan0
06:34:15.218947 IP 192.168.1.14.60082 > 183.77.202.242.80: Flags
[F.], seq 2386135769, ack 94445475, win 2641, options [nop,nop,TS val
104723161 ecr 2033111718], length 0
前の例では、クライアントアプリは60063番ポートを使用したが、今回は60082番ポートを使用している。このように、クライアントアプリは、49152番から65535番のポート番号を動的に使用する。

TCP

トランスポート層のTCPは、高品質なデータ通信を可能にする。アプリケーション層では、これを利用したものがいくつもある。それらはユーザに対して、さまざまなものを提供する。

  • テキスト
  • メッセージ
  • 音声
  • 動画

telnet

telnetコマンドを使用すると、ユーザは簡単にTCPのサービスを受けることができる。telnetは指定したIPアドレスのポート番号に対し、ユーザが入力した文字列を送信する。本稿では、これを利用してHTTPやSMTP、POP3などのプロトコルを説明する。


Web(HTTP)

WWW(World Wide Web)上でテキストや画像などのデータを通信するのに使用されている代表的なプロトコルが、HTTP(Hyper Text Transfer Protocol)である。HTTPサーバは基本的にTCPポートの80番を使用し、クライアントが要求したテキストや画像などを送信する。HTTPクライアントとして最も有名なアプリケーションがWebブラウザである。Webブラウザにはさまざまな種類がある。

  • Internet Explorer
  • Firefox
  • Google Chrome
  • Safari

ユーザの中にはWebブラウザが表示したWebページを、Web(HTTP)サーバが提供している画面だと認識しているかもしれない。しかしHTTPクライアントが取得するデータは、基本的にHTML(Hyper Text Markup Language)という形式のテキストである。HTTPのバージョン1.0では、クライアントは次のようにGETメソッドを使用してHTMLテキストを取得できる。

user% telnet pied-piper.net 80
Trying ::1...
Connected to pied-piper.net.
Escape character is '^]'.
GET /index.html HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 14 Apr 2014 15:34:24 GMT
Server: Apache/2.2.22 (Debian)
Last-Modified: Sat, 21 Sep 2013 17:22:33 GMT
ETag: "6a2c55-b1-4e6e8084eb7e3"
Accept-Ranges: bytes
Content-Length: 177
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8

<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added,
      yet.</p>
</body></html>
Connection closed by foreign host.
HTTPの仕様についてはRFCを参照されたし。
バージョンRFC
HTTP/1.0RFC 1945
HTTP/1.1RFC 2616

HTML(Hyper Text Markup Language)

HTTPは基本的にHTMLという形式のテキストを転送する。HTMLはマークアップ言語とよばれるコンピュータ言語の一種である。マークアップ言語はタグという文字列を使って、各文章を意味付けできる。例えば<h1>ハロー</h1>は"ハロー"という文字列が文中の最大レベルの見出しであることを示す。タグは基本的にマークしたい文字列を囲うことで意味付けする。以下にサンプルコードを示す。

<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added,
      yet.</p>
</body></html>
<html>-</html>
HTMLの文
<body>-</body>
本文
<h1>-</h1>
見出し レベル1-6(1が最大)
<p>-</p>
段落

HTMLレンダリングエンジン

WebブラウザはHTMLを受け取るとそれを読み込み、解釈してユーザに分かりやすい形で表現する。前述で紹介したWebブラウザの場合、HTMLを視覚的に見やすい形で表現する。前述のサンプルを表現した例が次の通りである。

HTML Rendering Engine
ただし必ずしも視覚的な表現だけとは限らず、視覚障害者用の音声ブラウザのように音声で表現するものもある。このHTMLを取得し、それを解釈してユーザに分かりやすいよう表現するプログラム、または機能をHTMLレンダリングエンジンという。最近のHTMLレンダリングエンジンの多くはHTMLだけでなく、CSS(Cascading Style Sheets)JavaScriptなどを読み込む機能を持つ。
CSS(Cascading Style Sheets)
HTMLの視覚的情報を指定する情報。例えば文字の色や大きさなどがある。
JavaScript
動的なWebサイトを構築するためのプログラミング言語。HTTPのクライアントであるWebブラウザによって読み込まれ、処理される。
HTMLレンダリングエンジンには、次のようなものがある。
HTMLレンダリングエンジンWebブラウザ
Trident
  • Internet Explorer
  • Sleipnir
  • Craving Explorer
Gecko
  • Firefox
  • Epiphany(後にWebKitに移行)
WebKit
  • Google Chrome
  • Safari
HTMLには基本的に視覚的情報がない。また、HTMLレンダリングエンジンによって独自のCSSのプロパティがある。それゆえ、HTMLレンダリングエンジン毎に表示される画面が同じであるとは限らない。

WebKitライブラリ

オープンソースのHTMLレンダリングエンジンであるWebKitを使用したプログラミングのサンプルを以下に示す。

#!/usr/bin/python2.7

import gtk
import webkit

win = gtk.Window()
web = webkit.WebView()
web.open("http://www.google.co.jp")
win.add(web)
win.show_all()
Debian7.10では"python-webkit-dev"というパッケージをインストールすることで、環境を整えることができる。


電子メール(SMTP, POP3)

電子メールとは、コンピュータネットワークを使って、メッセージやファイルなどのデータの送受信を行う手段のこと。電子メールはメールやEメールなどと略される。本稿ではメールと記述する。

メールの機能は、メールサーバメールクライアントによって実装される。

メールクライアント
ユーザはメールクライアントによってメールサービスを受けることができる。メールクライアントの機能は、メールサーバに保存されているメールを受け取ったり、メールサーバに頼んでメールを送ってもらったりする。
メールサーバ
メールの転送は各メールサーバが行う。

メールの送信から受信までの流れ

メールの実装にはアプリケーション層のいくつかのプロトコルが使用される。

プロトコル機能ポート
POP3(Post Office Protocol version3)メールサーバからメールを受け取る(POPとIMAPそれぞれに利点と欠点がある)。tcp/110
IMAP(Internet Message Access Protocol)tcp/143, tcp/220
SMTP(Simple Mail Transfer Protocol)メールを転送する。tcp/25
あるユーザがメールを送信し、別のユーザがメールを確認するまでの流れは次の通りである。
メールサーバは、それぞれドメイン(例:pied-piper.net)を持つ。
  1. メールクライアントはSMTPクライアントとして、自身のドメインのメールサーバのSMTPサーバ機能に対して、送信要求を行う。
  2. SMTPサーバはメールの宛先が自身のドメインであれば、設定されたメールボックスにそれを追加する。それ以外の場合、その宛先ドメインのメールサーバのSMTPサーバ機能に対し、SMTPクライアントとして送信要求を行う。
  3. 受信するユーザは、POP3やIMAPクライアントでメールサーバにアクセスすることで、自身宛に届いたメールを受け取ることができる。

電子メールの仕組み

メールは5つのプログラム(機能)によって構成される。以下にそれらのプログラムとメールの流れを紹介する。

MUA(Mail User Agent)
いわゆるメールクライアントのこと。他にもメーラ、メールリーダなどと呼ばれる。
MTA(Mail Transfer Agent)
メールを別のメールサーバに送信したりMDAに渡したりするもの。
MDA(Mail Delivery Agent)
MTAから受け取ったメールをメールボックスに保存するもの。
MRA(Mail Retrieval Agent)
メールを受信するもの。
MSA(Mail Submission Agent)
MUAとMTAの間で認証などを行うもの。メールの仕組みができたばかりのころはなかったが、現在はセキュリティのためにMSAを間に置くのが主流。

メールクライアント

前述のHTTPのサンプルと同様に、telnetを使ってSMTPとPOP3のサーバにアクセスした例を以下に示す。

SMTP
user% telnet 192.168.1.101 25
Trying 192.168.1.101...
Connected to versus.
Escape character is '^]'.
220 pied-piper.net ESMTP
HELO pied-piper.net
250 pied-piper.net
MAIL FROM: me@pied-piper.net
250 ok
RCPT TO: user@pied-piper.net
250 ok
DATA
354 go ahead
From: me@pied-piper.net
Subject: test

Hello, User
.
250 ok 1397490184 qp 6800
QUIT
221 pied-piper.net
Connection closed by foreign host.
ちなみにSMTPの通信には,DATA以前に入力した情報を使用し,それ以降はメールヘッダのために使用する。 それゆえヘッダ部分は,偽装することも可能であるが,いくつかのSMTPサーバは,そのような怪しいメールの受け取りを拒否する。
POP3
user% telnet 192.168.1.101 110
Trying 192.168.1.101...
Connected to versus.
Escape character is '^]'.
+OK <6798.1397490101@pied-piper.net>
USER user
+OK
PASS hogehoge
+OK
STAT
+OK 125 3714019
LIST
+OK 
1 754
2 1846
3 782
RETR 1
+OK 
Return-Path: <user@pied-piper.net>
Delivered-To: user@pied-piper.net
Received: (qmail 6615 invoked by uid 0); 15 Apr 2014 00:22:33 +0900
Received: from unknown (HELO pied-piper.net) (192.168.1.111)
  by 192.168.1.101 with SMTP; 15 Apr 2014 00:22:33 +0900
From: me@pied-piper.net
Subject: test
Hello, User

.

QUIT
+OK 
Connection closed by foreign host.

SMTP,POP3プログラミング

SMTPやPOP3ライブラリを使用したサンプルコードを以下に示す。

SMTP
#!/usr/bin/python2.7

import smtplib,email.utils
from email.mime.text import MIMEText

FROM = "i@pied-piper.net"
TO = "you@example.pied-piper.net"

msg = MIMEText('This is the body of the message.')
msg['To'] = email.utils.formataddr(('You', TO))
msg['From'] = email.utils.formataddr(('O_Messiaen', FROM))
msg['Subject'] = 'Hello'

server = smtplib.SMTP('192.168.1.101', 25)
server.set_debuglevel(True) # show communication with the server
try:
    server.sendmail(FROM, [TO], msg.as_string())
finally:
    server.quit()
POP3
#!/usr/bin/python2.7

import poplib

pop3 = poplib.POP3("192.168.1.201", 110)
pop3.user("user")
pop3.pass_("hogehoge")
retr = pop3.retr(len(pop3.list()[1]))
"\n".join(retr[1])


セッション層

OSI参照モデル(7階層モデル)では,アプリケーション層とトランスポート層の間に,プレゼンテーション層とセッション層がある。セッション層では,通信の開始時や終了時などに送受信するデータの形式などを規定する。セッション層には例えばSSL(Secure Socket Layer)がある。SSLの詳細は省略するが,それは階層の上位のレイヤに対して暗号化や認証,完全性を提供する。昨今,httpやsmtp,pop3などのアプリケーション層のプロトコルを安全に利用するために,SSLを利用することは珍しくない。

以下にSMTP-SSLの利用例を示す。ここではopensslコマンドを使用する。opensslの機能はさまざまあり,引数としてコマンドを指定する。 以下の例では,s_clientを使用する。telnetやnc(netcat)がTCP(トランスポート層)での通信を提供するソフトウェアと考えるなら,opensslのs_clientコマンドはSSL(セッション層)での通信を提供するソフトウェアと考えれば良い。オプションの詳細については"man s_client"で閲覧できる。

user% openssl s_client -connect smtp.gmail.com:465 -crlf -ign_eof
CONNECTED(00000003)
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIIGcMF7jeVMoAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
   ー中略ー
    Verify return code: 20 (unable to get local issuer certificate)
---
220 mx.google.com ESMTP n7sm9349346pdl.90 - gsmtp
EHLO localhost
250-mx.google.com at your service, [153.198.XXX.XXX]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
認証方法を入力する。
AUTH LOGIN
334 VXNlcm5hbWU6
AUTH LOGINで認証を行う場合,ユーザ名とパスワードをそれぞれbase64でエンコードしたものを使用する。ここでXXXXXXXXXXはユーザ名をエンコードしたもの,YYYYYYYYYYはパスワードをエンコードしたものである。
XXXXXXXXXX
334 UGFzc3dvcmQ6
YYYYYYYYYY
235 2.7.0 Accepted
エンコードは,次のようにbase64コマンドやopensslのencコマンドで行うことができる。また,opensslのencコマンドのマニュアルはs_clientと同様"man enc"で閲覧できる。
  • user% echo "me@gmail.com" | base64 
    bWVAZ21haWwuY29tCg=
  • user% echo "me@gmail.com" | openssl enc -e -base64
    bWVAZ21haWwuY29tCg=
パスワードのエンコードも同様である。XXXXXXXXXXやYYYYYYYYYYの部分にはこの結果を貼り付ければ良い。 これ以降は通常のSMTPと同じように行えば良いが,ここではあえてHTMLメールを送信する例を紹介する。
MAIL From: <me@gmail.com>
250 2.1.0 OK n7sm9349346pdl.90 - gsmtp
RCPT To: <you@gmail.com>
250 2.1.5 OK n7sm9349346pdl.90 - gsmtp
DATA
354  Go ahead n7sm9349346pdl.90 - gsmtp
Subject: html-mail
Mime-Version: 1.0;
Content-Type: text/html; charset="ISO-8859-1";
Content-Transfer-Encoding: 7bit;

<!DOCTYPE HTML>
<html lang="ja-JP">
<body>
<h1>こんにちわ</h1>
</body>
<html>
.
250 2.0.0 OK 1413388691 n7sm9349346pdl.90 - gsmtp
QUIT
221 2.0.0 closing connection n7sm9349346pdl.90 - gsmtp
read:errno=0

HTMLタグとCSSによるデフォルメ日本地図

投稿日:
タグ:

tableタグとCSSで書くデフォルメ日本地図。「タグで作った日本地図素材-地方別色分けB(リンクあり)」「なぜ人はテーブルタグで日本地図を作るのか - 寄せては返す館主専用」を参考に,HTMLとCSSで記述。

<style>
<!--
table.jp td {
    text-align:center;
    padding:5px;
}
td.hokkaido{
    background-color:#87cefa;
}
td.tohoku {
    background-color:#40e0d0;
}
td.koshinetsu {
    background-color:#3cb371;
}
td.hokuriku {
    background-color:#2e8b57;
}
td.kanto {
    background-color:#66cdaa;
}
td.kinki {
    background-color:#bdb76b;
}
td.tokai {
    background-color:#9acd32;
}
td.chugoku {
    background-color:#deb887;
}
td.kyusyu {
    background-color:#ff8c00;
}
td.shikoku {
    background-color:#ff7f50;
}
td.okinawa {
    background-color:#ff6347;
}
-->
</style>
<table class="jp">
<tr>
 <td colspan="15"></td>
 <td colspan="3" class="hokkaido" style="height:80px;">
  北海道
 </td>
</tr>

<tr>
<td></td>
</tr>

<tr>
<td colspan="15"></td>
<td colspan="2" class="tohoku">
青森
</td>
<td style="min-width:10px;"></td>
</tr>

<tr>
<td colspan="15"></td>
<td class="tohoku">
秋田
</td>
<td class="tohoku">
岩手
</td>
</tr>

<tr>
<td colspan="15"></td>
<td class="tohoku">
山形
</td>
<td class="tohoku">
宮城
</td>
</tr>

<tr>
<td colspan="12"></td>
<td class="hokuriku">
石川
</td>
<td class="hokuriku">
富山
</td>
<td class="koshinetsu" colspan="2">
新潟
</td>
<td class="tohoku">
福島
</td>
</tr>

<tr>
<td colspan="2"></td>
<td class="kyusyu">
長崎
</td>
<td class="kyusyu">
佐賀
</td>
<td class="kyusyu">
福岡
</td>
<td></td>
<td class="chugoku" rowspan="2">
山口
</td>
<td class="chugoku">
島根
</td>
<td class="chugoku">
鳥取
</td>
<td class="kinki" rowspan="2">
兵庫
</td>
<td class="kinki">
京都
</td>
<td class="kinki">
滋賀
</td>
<td class="hokuriku">
福井
</td>
<td class="koshinetsu" rowspan="2">
長野
</td>
<td class="kanto">
群馬
</td>
<td class="kanto">
栃木
</td>
<td class="kanto">
茨城
</td>
</tr>

<tr>
<td colspan="3"></td>
<td class="kyusyu">
熊本
</td>
<td class="kyusyu">
大分
</td>
<td></td>
<td class="chugoku">
広島
</td>
<td class="chugoku">
岡山
</td>
<td class="kinki">
大阪
</td>
<td class="kinki">
奈良
</td>
<td class="tokai">
岐阜
</td>
<td class="koshinetsu">
山梨
</td>
<td class="kanto">
埼玉
</td>
<td class="kanto">
千葉
</td>
</tr>

<tr>
<td colspan="3"></td>
<td class="kyusyu">
鹿児島
</td>
<td class="kyusyu">
宮崎
</td>

<td colspan="5"></td>

<td class="kinki">
和歌山
</td>
<td class="tokai">
三重
</td>
<td class="tokai">
愛知
</td>
<td class="tokai">
静岡
</td>
<td class="kanto">
神奈川
</td>
<td class="kanto">
東京
</td>
</tr>

<tr>
<td colspan="7"></td>
<td class="shikoku">
愛媛
</td>
<td class="shikoku">
香川
</td>
</tr>

<tr>
<td class="okinawa">
沖縄
</td>
<td colspan="6"></td>
<td class="shikoku">
高知
</td>
<td class="shikoku">
徳島
</td></tr>
</table>

videoタグとaudioタグ

投稿日:
編集日:
タグ:

本稿はvideoタグとaudioタグに関するメモ。 参考にしたものとしては,このページなどを利用した。

videoタグ

動画を扱うためのタグ。どうやらWebブラウザはちゃんとバッファリングしてくれるようだった。

動画はWebで検索して見つかった動画素材を使用。ソースコードはこのような感じである。
<video controls width="320" height="240">
<source src="./downloads/a63/test.mp4">
<p>ご利用のWebブラウザでは再生できません。</p>
</video>
videoタグやaudioタグで囲んだものはそのタグをサポートしていないブラウザ向けの内容を書く。

再生できる動画フォーマットはWebブラウザに依存するが,videoタグはsourceタグを使用することでいくつかの候補を用意することができる。

<video controls autoplay poster="firstframe.jpg" width="320"
height="240">
<source src="./sample.flv">
<source src="./sample.mp4">
<p>ご利用のWebブラウザでは再生できません。</p>
</video>
videタグの属性には次のようなものがある。
controls
再生やシーク,音量などのインタフェースを表示。
autoplay
読み込み次第再生。
poster
初期画面。
width
横のサイズ。
height
縦のサイズ。

CSSやJavascriptを利用したコメント付き動画のサンプル

videoタグやCSS,Javascriptを使用すればニコニコ動画のように動画にコメントが流れるようなものも生成できる。以下にサンプルを示す。なお停止やシークの移動によりコメントが戻るような機能はついていない。また,サンプルでは追加されたタグは削除されないので注意。

CSS
div#comments {
  position:absolute;
  width:420px;
  height:200px;
  color:black;
  z-index:1;
  font-size:20px;
  text-align:center;
  opacity:0.7;
}

video#comments_video {
    z-index:0;
    position:absolute;
    padding-left:100px;
}
Javascript
const ID = 0;
const COMMENT = 1;
const START = 2;
const LEFT = 3;
const TOP = 4;
const DEFAULT_LEFT = 420
const COMMENT_NUM = 11;
var comments = [
    // [element, comment, start_time, default_left, top]
    [null, "comment0", 0, DEFAULT_LEFT, 60],
    [null, "comment1", 1000, DEFAULT_LEFT, 40],
    [null, "comment2", 1000, DEFAULT_LEFT, 80],
    [null, "comment3", 2000, DEFAULT_LEFT, 40],
    [null, "comment4", 3000, DEFAULT_LEFT, 140],
    [null, "comment5", 5000, DEFAULT_LEFT, 40],
    [null, "comment6", 5000, DEFAULT_LEFT, 80],
    [null, "comment7", 5000, DEFAULT_LEFT, 100],
    [null, "comment8", 6000, DEFAULT_LEFT, 80],
    [null, "comment9", 6500, DEFAULT_LEFT, 100],
    [null, "comment10", 7000, DEFAULT_LEFT, 160]
];
var rtime;
var time=0;
var min = 0;
var index=0;

function controlComments()
{
    var child;
    
    time += 50;
    if (index < COMMENT_NUM)
	while (comments[index][START] < time){
	    comments[index][ID] = document.createElement("span");
	    child = comments[index][ID];
	    document.getElementById("comments").appendChild(child)
	    child.innerHTML = comments[index][COMMENT];
	    child.style.color = "black";
	    child.style.position = "absolute";
	    child.style.left = comments[index][LEFT] + "px";
	    child.style.top = comments[index][TOP] + "px";
	    document.getElementById("comments").appendChild(comments[index][ID])
	    index += 1;
	}
    
    
    for (i=min;i<index;i++){
	if (comments[i][LEFT] > 0){
	    comments[i][LEFT] -= 5;
	    comments[i][ID].style.left = comments[i][LEFT] + "px";
	}else{
   	    // TODO: spanタグの削除
	    if (i>min)
		min = i;
	}
    }
}

function doPlay()
{
    rtime = setInterval('controlComments()', 50);
}

function doPause()
{
    clearInterval(rtime);
}
html5
<div id="comments">
</div>

<video id="comments_video" controls poster="firstframe.jpg" onplay="doPlay();" onpause="doPause()" width="320" height="240">
<source src="./downloads/a63/test.mp4">
<p>動画を再生するにはvideoタグをサポートしたブラウザが必要です。</p>
</video>

audioタグ

音楽を扱うためのタグ。 audioタグもvideoタグ同様controls属性を使えるが,以下にjavascriptやhtml,cssでインタフェースを作成した例を示す。



曲はWebで検索したものから適当なページを選択。

css3
hr {
    display:none;
}

section#music_controller {
    background-color:black;
    text-align:center;
    width:20em;
    padding:1em;
}

select {
    background-color:#111111;
    color:white;
    width:20em;
}

#music_seek {
    height:2em;
    width:20em;
}

.cir_btn {
    color:red;
    background-color:black;
    text-align:center;
    width:3em;
    height:3em;
    margin:0;
    padding:2px;
    border-radius: 30px;
    -moz-border-radius: 30px;
    -webkit-border-radius: 30px;
}
javascript
var playing = false;	// 再生中か否か
var rtime;		// シークバーの管理
var idx=0;		// 音楽番号
var MUSIC_NUM=3;	// 曲数
var MUSIC_LIST = [	// 曲名一覧
    "http://pied-piper.net/note/downloads/a63/Brahms-Symphony-No1-1st.mp3",
    "http://pied-piper.net/note/downloads/a63/Ravel-Bolero.mp3",
    "http://pied-piper.net/note/downloads/a63/Beethoven-SymNo7-1.mp3"
];


/* 再生位置をシークバーの位置に設定 */
function jumpMusicSeek()
{
    document.getElementById("my_audio").currentTime = document.getElementById("music_seek").value;
}


/* 曲名を指定した番号に変更 */
function changeMusic(i)
{
    if (playing)
	stopMusic();
    
    idx = i;
    document.getElementById("my_audio").src = MUSIC_LIST[idx];
    document.getElementById("music_list").selectedIndex = idx;
}


/* 選択された曲を再生 */
function selectMusic()
{
    if (playing)
	stopMusic();
    
    idx = document.getElementById("music_list").selectedIndex;
    document.getElementById("my_audio").src = MUSIC_LIST[idx];
    
    playMusic();
}


/* シークバーを進める */
function advanceMusicSeek()
{
    var audio = document.getElementById("my_audio");
    if (audio.ended){
	idx++;
	if (idx<MUSIC_NUM){
	    changeMusic(idx);
	    playMusic();
	}else{
	    idx = 0;
	    changeMusic(idx);
	}
    }
    document.getElementById("music_seek").value = audio.currentTime;
}


/* 次の曲を再生 */
function nextMusic()
{
    idx++;
    if (idx >= MUSIC_NUM){
        idx = 0;
    }
    if (playing){
        changeMusic(idx);
        playMusic();
    }else{
        changeMusic(idx);
    }
}


/* 前の曲を再生 */
function prevMusic()
{
    idx--;
    if (idx < 0){
        idx = MUSIC_NUM-1;
    }
    if (playing){
        changeMusic(idx);
        playMusic();
    }else{
        changeMusic(idx);
    }
}


/* 曲を再生/一時停止 */
function playMusic()
{
    if (playing){
	document.getElementById("play_button").innerHTML = "▶";
	document.getElementById("my_audio").pause();
	playing = false;
	clearInterval(rtime);
    }else{
	var audio;
	var seek = document.getElementById("music_seek");
	audio = document.getElementById("my_audio");
	audio.play();
	document.getElementById("play_button").innerHTML = "||";
	playing = true;
	rtime = setInterval("advanceMusicSeek()", 500);
    }
}


/* 再生中の音楽を停止 & 再生位置を0に */
function stopMusic()
{
    var audio = document.getElementById("my_audio");
    if (playing){
	audio.pause();	
	document.getElementById("play_button").innerHTML = "▶";
	document.getElementById("my_audio").pause();
	playing=false;
	clearInterval(rtime);
    }
    audio.currentTime = 0.0;
    document.getElementById("music_seek").value = audio.currentTime;
}


/* 早送り */
function ffMusic()
{
    audio = document.getElementById("my_audio");
    audio.currentTime += 2.0;
    document.getElementById("music_seek").value = audio.currentTime;
}


/* 巻き戻し */
function rewindowMusic()
{
    audio = document.getElementById("my_audio");
    audio.currentTime -= 2.0;
    document.getElementById("music_seek").value = audio.currentTime;
}


/* 曲の再生時間を設定 */
function setMaxTime()
{
    document.getElementById("music_seek").max = document.getElementById("my_audio").duration;
}
html5
<div id="music_player">
<section id="music_controller">
<button id="prev_button" onClick="prevMusic()" class="cir_btn">|◀◀</button>
<button id="rewind_button" onClick="rewindMusic()" class="cir_btn">◀◀</button>
<button id="play_button" onClick="playMusic()" class="cir_btn">▶</button>
<button id="stop_button" onClick="stopMusic()" class="cir_btn">■</button>
<button id="ff_button" onClick="ffMusic()" class="cir_btn">▶▶</button>
<button id="next_button" onClick="nextMusic()" class="cir_btn">▶▶|</button>

<br>

<input id="music_seek" type="range" onChange="jumpMusicSeek()" min="0.0" value="0.0">

<br>

<select id="music_list" onChange="selectMusic()" size="3">




<option selected>ブラ1</option>
<option>ボレロ</option>
<option>ベト7</option>
</select>
</section>

<audio id="my_audio" src="http://www.sousound.com/music/jazz_fusion/jazz_01.mp3" onloadeddata="setMaxTime();">
<p>このブラウザはaudioタグをサポートしていません</p>
</audio>
</div>

JavaScriptコードレシピ

投稿日:
タグ:

本稿はJavascriptやHTML5,CSSを使ったコードレシピ集である(随時更新予定)。

ファイル生成

HTMLでボタンを押したら"Hello, World!"と記述されたテキストファイルを生成するには,次のようなコードを記述する。

<script>
function createFile(){
  blob = new Blob(["Hello, World!\n"]); 
  var anchor = document.createElement("a");
  var evt = document.createEvent("MouseEvent");

  anchor.download = "file.txt";
  anchor.href = (window.URL || window.webkitURL).createObjectURL(blob);
  evt.initEvent("click", true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
  anchor.dispatchEvent(evt);
}
<script>
<input type="button" onClick="createFile();" value="button">
IE

IE相手にで同じような処理を行わせたい場合,msSaveBlobやmsSaveOrOpenBlobメソッドを使用する方法がある。前者は保存させたい場合に,後者は保存か開くかを選ばせたい場合に使用する。使い方は同じであるが,ここではmsSaveBlobメソッドを使用した例を示す。

function createCSV(){
  var str = "得意先コード,得意先名,電話番号,住所 \n\
AX0001,山田太郎,999-999-9999,ほげ県ふが市ぴよ町0-0 \n\
BX0002,鈴木次郎,000-000-0000,ほげ県ふが市ぴよ町1-1 \n\
CX0003,佐藤三郎,111-111-1111,ほげ県ふが市ぴよ町0-0 \n\
DX0004,衛宮四郎,222-222-2222,ほげ県ばあ市ぴよ町0-0\n";
  var blobObject = new Blob([str], { type: "text/csv" });
  window.navigator.msSaveBlob(blobObject, 'file.csv');
}

私の環境では生成されたファイルの文字コードがUTF-8になったが,それをShift_JISとして生成する方法は次の通りである。

function createSJIS(){
  var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
  var str = "得意先コード,得意先名,電話番号,住所 \n\
AX0001,山田太郎,999-999-9999,ほげ県ふが市ぴよ町0-0 \n\
BX0002,鈴木次郎,000-000-0000,ほげ県ふが市ぴよ町1-1 \n\
CX0003,佐藤三郎,111-111-1111,ほげ県ふが市ぴよ町0-0 \n\
DX0004,衛宮四郎,222-222-2222,ほげ県ばあ市ぴよ町0-0\n";
  var blobObject = new Blob([bom, str], { type: "text/csv" });
  window.navigator.msSaveBlob(blobObject, 'hoge.csv');
}

ページ?

selectタグやinnerHTMLを使用してページを指定するようにして画面の表示を変更する例を以下に示す。

得意先コード得意先名電話番号住所
AX0001山田太郎999-999-9999ほげ県ふが市ぴよ町0-0
BX0002鈴木次郎000-000-0000ほげ県ふが市ぴよ町1-1

/2
<script>
var ary = ["AX0001山田太郎000-000-0000ほげ県ふが市ぴよ町0-0BX0001鈴木次郎000-000-0000ほげ県ふが市ぴよ町1-1","CX0001佐藤三郎000-000-0000ほげ県ふが市ぴよ町0-0DX0001衛宮四郎000-000-0000ほげ県ばあ市ぴよ町0-0"];
function changePage(){
  document.getElementById("cpage_tbody").innerHTML = ary[parseInt(this.cpage.value) - 1];
}
</script>

<div align="center">
  <table class="sep">
    <thead>
      <tr><th>得意先コード</th><th>得意先名</th><th>電話番号</th><th>住所</th></tr>
    </thead>

    <tbody id="cpage_tbody">
      <tr><td>AX0001</td><td>山田太郎</td><td>000-000-0000</td><td>ほげ県ふが市ぴよ町0-0</td></tr>
      <tr><td>BX0001</td><td>鈴木次郎</td><td>000-000-0000</td><td>ほげ県ふが市ぴよ町1-1</td></tr>
  </table>

  <br>

  <select id="cpage" name="cpage" onChange="changePage()">
    <option value="1" selected>1</option>
    <option value="2">2</option>
  </select>/2
</div>

jQueryの利用

投稿日:
修正日:
タグ:

jQueryとは,JavaScriptのコーディングを簡潔にしたり,強力にするためのライブラリである。本稿ではjQueryを使ったいろいろなサンプルを紹介する(随時更新予定)。

サンプル一覧

jQueryの基本

jQueryを使用する場合,はじめに通常のJavaScriptファイルと同様に,scriptタグを使ってファイルを読み込む。

<script type="text/javascript" src="〜">

指定するURLもまたローカルでもグローバルでも良い。

そしてjQueryを実際に利用したい場合は,$関数またはjQuery関数を使う。使い方は両者とも全く同じと考えても問題はないはず。

例えば後述するハッシュ値に変換する機能を利用したい場合,次のように記述する。

  • var str = "hoge";
    var hash = $.md5(str);
    
  • var str = "hoge";
    var hash = jQuery.md5(str);
    

また,タグに何らかの処理を行いたい場合は次のように記述する。

$("セレクタ").関数(引数)

補足すると,セレクタとは,CSSで記述しているidやクラス,擬似クラスなどのことである(hoge {color:red;}のhogeの部分)。この文では,セレクタで指定したタグに,指定した関数の処理を行う。

このような処理を行う場合,ページのDOMツリーが用意された状態でなければならない。そのため,そのような処理は次のような関数を使用する。

$(document).ready(実際に処理を行う関数);

これはwindow.onloadに似ているが,$(document).readyはwindow.onloadと異なり,HTML文書が完全にロードされなくてもHTMLをDOMツリーに変換した時点で処理される。ちなみにreadyは省略可能である。

$(function(){});

住所の補完

「郵便番号を入力すると住所を自動保管してくれるjQueryプラグイン・jquery.jpostal.js - かちびと.net」を参考。というかコードはほぼコピペ。

郵便番号 〒 -
都道府県
市区町村
町域
<div>
<script type="text/javascript" src="http://code.jquery.com/jquery-git2.js"></script>
<script type="text/javascript" src="http://jpostal.googlecode.com/svn/trunk/jquery.jpostal.js"></script>
<script type="text/javascript">
<!--
$(document).ready( function() {
  $('#postcode1').jpostal({
    postcode : [
      '#postcode1',
      '#postcode2'
    ],
    address : {
      '#prefecture'  : '%3',
      '#city'  : '%4',
      '#town'  : '%5'
    }
  });
});
-->
</script>
<form>


<span>郵便番号 〒</span>
<input id="postcode1" name="postcode1" maxlength="3">-<input id="postcode2" name="postcode2" maxlength="4"><br />

<span>都道府県</span>
<select id="prefecture" name="prefecture">
 <option value="北海道" selected>北海道</option>
 <option value="青森県">青森県</option>
 <option value="岩手県">岩手県</option>
 <option value="宮城県">宮城県</option>
 <option value="秋田県">秋田県</option>
 <option value="山形県">山形県</option>
 <option value="福島県">福島県</option>
 <option value="茨城県">茨城県</option>
 <option value="栃木県">栃木県</option>
 <option value="群馬県">群馬県</option>
 <option value="埼玉県">埼玉県</option>
 <option value="千葉県">千葉県</option>
 <option value="東京都">東京都</option>
 <option value="神奈川県">神奈川県</option>
 <option value="新潟県">新潟県</option>
 <option value="富山県">富山県</option>
 <option value="石川県">石川県</option>
 <option value="福井県">福井県</option>
 <option value="山梨県">山梨県</option>
 <option value="長野県">長野県</option>
 <option value="岐阜県">岐阜県</option>
 <option value="静岡県">静岡県</option>
 <option value="愛知県">愛知県</option>
 <option value="三重県">三重県</option>
 <option value="滋賀県">滋賀県</option>
 <option value="京都府">京都府</option>
 <option value="大阪府">大阪府</option>
 <option value="兵庫県">兵庫県</option>
 <option value="奈良県">奈良県</option>
 <option value="和歌山県">和歌山県</option>
 <option value="鳥取県">鳥取県</option>
 <option value="島根県">島根県</option>
 <option value="岡山県">岡山県</option>
 <option value="広島県">広島県</option>
 <option value="山口県">山口県</option>
 <option value="徳島県">徳島県</option>
 <option value="香川県">香川県</option>
 <option value="愛媛県">愛媛県</option>
 <option value="高知県">高知県</option>
 <option value="福岡県">福岡県</option>
 <option value="佐賀県">佐賀県</option>
 <option value="長崎県">長崎県</option>
 <option value="熊本県">熊本県</option>
 <option value="大分県">大分県</option>
 <option value="宮崎県">宮崎県</option>
 <option value="鹿児島県">鹿児島県</option>
 <option value="沖縄県">沖縄県 </option>
</select>
<br>

<span>市区町村</span>
<input type="text" id="city" name="city">
<br>

<span>町域</span>
<input type="text" id="town" name="town">
<br>

<input type="button" value="送信">
<input type="reset"  value="クリア">
</form>
</div>
住所の補完とinput:hidden

hiddenタイプの入力と組み合わせれば,前述の方法で住所を補完する場合でも1つの入力フォームの補完ができる。

郵便番号 〒 -

<script type="text/javascript">
$(function() {
  $('#postcode1').jpostal({
    postcode : [
      '#postcode1',
      '#postcode2'
    ],
    address : {
      '#prefecture'  : '%3',
      '#city'  : '%4',
      '#town'  : '%5'
    }
  });
});
</script>

<span>郵便番号 〒</span>
<input id="postcode1b" name="postcode1b" maxlength="3" style="width:3em">-<input id="postcode2b" name="postcode2b" maxlength="4" style="width:4em;">
<input type="button" value="補完" onClick="document.getElementById('addressb').value = document.getElementById('prefectureb').value + document.getElementById('cityb').value + document.getElementById('townb').value;">
<br>
<input type="text" id="addressb">
<input type="hidden" id="prefectureb" name="prefectureb">
<input type="hidden" id="cityb" name="cityb">
<input type="hidden" id="townb" name="townb">
<br>

<input type="reset"  value="クリア">
</form>
</div>

このサンプルでは,onClick属性にそのまま処理を記述しているが,当然ながら関数化した方が可読性は良い。


並び替え可能なウィジェット

タグを並び替えるjQueryには、Sortableを使用する。
  1. hoge
  2. fuga
  3. piyo
  4. foo
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script>
$(function() {
    $('#sortable').sortable();
});
</script>
<ol id="sortable">
 <li id="d01"><div>hoge</div></li>
 <li id="d02"><div>fuga</div></li>
 <li id="d03"><div>piyo</div></li>
 <li id="d04"><div>foo</div></li>
</ol>
説明
cursorドラッグ時のカーソルcursor: 'move'
opacityドラッグ時の透明度opacity: 0.6
updateドロップ時に実行する処理update: function(){〜}

ドラッグ可能なウィジェット

タグのドラッグ可能なjQueryには、Draggableを使用する。
ドラッグ可能
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script>
$(function() {
  $('#draggable').draggable({
    containment: 'parent'
  });
});
</script>
<div style="border:inset; width:100%; height: 3em;">
<div id="draggable" style="background-color:blue; width:6em;">
ドラッグ可能
</div>
</div>
説明
containmentドラッグ可能な範囲を制限containment: 'parent'
curssorドラッグ時のカーソルcursor:move
opacityドラッグ時の透明度opacity:0.8
revertドロップ後元の位置に戻すrevert:true
startドラッグ開始時の処理start: function(){〜}
dragドラッグ中の処理drag: function(){〜}
stopドラッグ終了時の処理stop: function(){〜}

一覧