日記帳

プログラミングのことをつぶやく日記です。

プロになるためのWeb技術入門 感想 読書感想

はじめに

Web業界に転職して、そろそろ1年が経過します。

今まで勉強した知識にどの程度抜け漏れがあるのか確認のために、今更ながら「プロになるためのWeb技術入門」を読みました。

改めて理解が促進した箇所、新たな発見があった箇所を列挙します。

なお、私の頭脳のワークスペースの都合上、書籍の前半部しかまとめられてないです。

プロになるためのWeb技術入門

リソースの位置を示すURL

URLの仕組みは、なんとなく使っているので、改めて復習しました。

URLは、ブラウザにアドレスバーに打ち込む文字列です。

インターネット上のコンテンツを一意に指定するための仕組みが「URL(Uniform Rsource Locator)なのです。

日本語に訳すと「統一資源位置子(とういつしげんいちし)」となります。

http :// /www.littleforest.jp / webtext/index.html
スキーム ホスト名 パス名

パーセントエンコード

https://www.test/index.php?name=%E3%83%86%E3%82%B9%E3%83%88

インターネットサーフィンをしてるとURLに「%」が混じることがありますよね

URLは全角文字は使用できないので、ブラウザ側がサーバーでも読み取れる文字にエンコードしてくれます。

これが「パーセントエンコード」です。

スキーム

そもそもhttpsとは何なんか最初のうちはよくわかりませんでした。

スキームは、リソースを取得するための方法を表します。Webアプリケーションにえいては、ほとんどの場合「http」となります

スキーム名 説明
https 暗号化されたhttp通信を表すスキーム
mailto 電子メールの宛先を表すスキーム
ftp FTPプロトコルによる入手を表すスキーム
file ファイルシステム中のファイルやディレクトリを参照するためのスキーム

業務では、httpsftpはよく触れる印象があります。

URLとURIの違い

他のWeb技術の基礎本を読んでいるときに、URLという単語という単語がほぼ登場せず、代わりにURIという単語で使われていることがあります。

URLとURIの違いはなんでしょうか。

URIは、URLをより拡張した概念として、URI(Uniform Resource Idenrifier)が考え出されたのです。

URIとは、URLに加えて「URN(Uniform Rsource Name)」を合わせたものを指します。

URNはインターネット上に存在する名前を一意に識別するために用意されたものです。

URLの場合は、ホストが移動すると移動先のURLを知らないとアクセスできなくなります。

URNは、このようなリソースの移動に関しての問題を解決するために、インターネット上に存在するリソースに対しては統一的な名前を決めようと考え出されたものです。

例えば、「nrn:itif:rfc:2616」は、HTTP1.1のRFCに対するURNです。この文書が物理的にどのような位置に存在しようと、同じURNで指し示すことができるというわけです。

現状ではURNはあまり利用されておらず、実質的にはURIもURLもほぼ同じ意味で扱われています。

混乱の元はURIとURLもほぼ同様の意味で使用されているため、なぜ2種類もの呼び方があるのか理解できないことです。

このように背景を理解してしまえば、理解しやすいですね。

Webベンチャーで働いている人に、あまり馴染みのないサーブレットJSP

PHPRubyでアプリケーションを作っていると、Javaに対してあまり馴染みがありません。

しかしJavaエンタープライズでのWeb開発で使用されている言語、歴史的変遷だけでも知っておくのがいいかと思いました。

サーブレットの誕生

Webが普及しCGIが一般的になると、新たな問題が生まれました。

1つはPerlの仕様による問題、もう一つは多数のリクエストによるアクセス負荷の増大する問題です。

Java自体はWebアプリケーションのために開発された言語ではありません。しかし、Webアプリケーションは当時企業に置けるシステム開発でも主流になりつつありました。

そこで、JavaEE(Java Enterprise Edition)の一部として「サーブレット(Servlet)」というWebアプリケーション開発をサポートするため目の機能が供給されるようになったのです。

サーブレットJavaで作られたHTMLなどのWebコンテンツを生成するためのプログラムのことで、CGIを経由して起動されるPerlC言語Java版に相当します。

サーブレットは基本的にCGIと同じ考え方ですが、コンテンツを生成する言語がJavaであり、オブジェクト志向のサポートによって大規模アプリケーションの開発に向いていることと、Webサーバーと同じプロセスの中でコンテンツを生成するプログラムが動作するため、CGIのように新たなプロセスを毎回起動する必要がなく、比較的高速に動作するということが利点でした。

Javaの優れた特徴をWebの世界に持ち込み、発展させたということですね。

ただJavaエンタープライズ要素が強いので、なかなか個人開発では使用する機会がないです。

サーブレットのコードの例はこんな感じです。

mport java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Calc extens HttpServlet {
    public void doGet(HttpServletRequest request,
        HttpServletResponse response)
        throws ServletEception,IOException {
        // コンテキストタイプの設定
        response.setContentType("text/html;charset=Shift_JIS");

        // HTML出力の準備
        PrintWriter out=response.getWriter();

// HTMLの出力
    out.println("<html><head>");
    out.println("<title>Calcurator</title>");
    out.println("</head><body>");
    out.println("<p>1000円の税込み価格 ="+ (1000 * 1.08) +"円</p>");
    out.println("</body></html>");

// HTML出力の完了処理
out.flush();
out.close();
    }
}

今見ると可読性が悪いですね。

HTML部分を追うのに一苦労です。

サーブレットのコードは、レガシーPHPに通づるものがあると考えています。

サーブレットの弱点を改善したJSP(Java Server Pages)の誕生

サーブレットの弱点は、画面デザインの変更が初制するたびに、プログラムの変更が必要になること。

さらに、Javaソースコードの中にHTMLが点在するため、可読性が悪いことです。

この弱点、ノンフレームワークPHPプロジェクトに類似する部分がありますよね

これを解消したものがJSP(Java Server Pages)です。

先ほどのサーブレットソースコードJSPに置き換えます。

<html>
<head>
<title>Calcurator</title>
</head>
<body>
<p>1000円の税込価格 = <% out.println(1000 * 1.08); %> 円</p>
</body>
</html>

これってRailsとかCakePHPのview部分に似てますね。

用途の近しい技術は類似していくんですね。

感想

最初は自分用のまとめにしようと思ったのですが、段々熱が入り、少しでもまとめようという気持ちが出てきました。

しかし、読み手を考えると、書籍の感想のまとめは難しく、結局前半部分しかまとめられませんでした。

後半は、何か別の書籍とミックスしたいと思います。

S3にアップロードしようと思ったら、時計がズレていたので失敗した。

S3にアップロードしようと思ったら、時計がズレていたので失敗した。

環境

S3にアップロードしようと思ったら失敗した。

S3にアップロードしようと思ったら、以下のメッセージが返ってきました。

The difference between the request time and the current time is too large.

日本語訳:リクエストサーバーとS3の時間のズレが大きすぎる

同様の問題の解決記事

[Rails] 時計のズレが原因でS3への画像アップロードが失敗した

原因は、S3のサーバー時刻とWebサーバー時刻にズレがあったため

まずntpdateで自分のサーバーの時刻と日本標準時間を同期します。 Webサーバーは、vagrantを使用しています。

$ sudo ntpdate ntp.nict.jp
 6 Aug 14:02:10 ntpdate[7681]: adjust time server 133.243.238.244 offset 0.003161 sec

## ntpdateとは

ntpdateコマンドでは、日付と時刻をNTPサーバーと同期するコマンドです。

ntpdate - 日付と時刻をNTPサーバーと同期 - Linuxコマンド

以下ntpd関連資料

NTPサーバー構築(ntpd)

14.4. ntpd の起動と動作確認

ntpdデーモンの設定を変更したので、ntpdを再起動しましょう。

$ sudo /etc/rc.d/init.d/ntpd restart
ntpd を停止中:                                             [  OK  ]
ntpd を起動中:                                             [  OK  ]

これでOK!!

【PHP】特定の文字列が含まれているか調べたい

仕事で、文字列の中に、特定の文字列があるか調べる必要がありました。
正規表現を書くのも面倒だと思ってPHPマニュアルを漁っていたら、便利な’mb_strpos()’関数がありました。
簡単に’mb_strpos()’関数と、それとよく似た’mb_stripos()’関数を検証します。

mb_strpos
http://php.net/manual/ja/function.mb-strpos.php

mb_stripos
http://php.net/manual/ja/function.mb-stripos.php

mb_strpos()関数

「文字列A」の中に「文字列B」が存在するかどうか検索し、最初に見つかった位置を数値で返します。(先頭は0から始まります)
見つからなかった場合はfalseが返されます。

詳しい検証は、ソースコードを見ていきましょう。

<?php
$keyword_uppercase = 'XYZ';
$keyword_lowercase = 'xyz';

$text1 = 'abcXYZ';
$text2 = 'abcXYZabcXYZ';

// mb_strposの挙動

// 大文字は文字は含まれていると判定される
if (mb_strpos($text1, $keyword_uppercase) === false) {
    echo $keyword_uppercase . "は含まれていません" . "\n";
} else {
    echo $keyword_uppercase . "は含まれています" . "\n";
    echo mb_strpos($text1, $keyword_uppercase) . "文字目" . "\n";
}

// 小文字は含まれていないと判定される
if (mb_strpos($text1, $keyword_lowercase) === false) {
    echo $keyword_lowercase . "は含まれていません" . "\n";
} else {
    echo $keyword_lowercase . "は含まれています" . "\n";
    echo mb_strpos($text1, $keyword_lowercase) . "文字目" . "\n";
}

// 検索対象の文字列の中に、キーワードが複数含まれていても最初にマッチングした位置を返す
if (mb_strpos($text2, $keyword_uppercase) === false) {
    echo $keyword_uppercase . "は含まれていません" . "\n";
} else {
    echo $keyword_uppercase . "は含まれています" . "\n";
    echo mb_strpos($text1, $keyword_uppercase) . "文字目" . "\n";
}

実行結果

XYZは含まれています
3文字目
xyzは含まれていません
XYZは含まれています
3文字目

mb_stripos()関数

ここで不便なのが、小文字にマッチングしないことです。
SQL文の文字列をマッチングさせようとしても、
’SELECT * FROM table;’
’select * from table’
どちらも有効なクエリなため、’mb_strpos()’関数だと抜け漏れが発生します。
そこで便利なのが’mb_stripos()’関数です。
こちらは、大文字小文字の区別無しに文字列の有無を判定します。

こちらも検証のソースコードを見ていきましょう。

<?php
$keyword_uppercase = 'XYZ';
$keyword_lowercase = 'xyz';

$text1 = 'abcXYZ';

// mb_striposの挙動

// 大文字は文字は含まれていると判定される
if (mb_stripos($text1, $keyword_uppercase) === false) {
    echo $keyword_uppercase . "は含まれていません" . "\n";
} else {
    echo $keyword_uppercase . "は含まれています" . "\n";
    echo mb_stripos($text1, $keyword_uppercase) . "文字目" . "\n";
}

// 小文字も文字は含まれていると判定される
if (mb_stripos($text1, $keyword_lowercase) === false) {
    echo $keyword_lowercase . "は含まれていません" . "\n";
} else {
    echo $keyword_lowercase . "は含まれています" . "\n";
    echo mb_stripos($text1, $keyword_lowercase) . "文字目" . "\n";
}

実行結果

XYZは含まれています
3文字目
xyzは含まれています
3文字目

これだったら、大文字小文字区別なくマッチング判定できますね。

mb_strpos()関数の戻り値の誤判定

最後に’mb_strpos()’関数の誤判定について検証します。

‘mb_strpos()’関数の戻り値がfalseかどうか判定する場合、「==」演算子ではなく、必ず「===」演算子を使って判定してください。「==」演算子を使って判定した場合、0とfalseが同じ値だと判定されてしまうため、’mb_strpos()’関数が0を返した場合に誤判定が生じます。

<?php
// mbstrposの誤判定
$keyword2 = 'DEF';

$text2 = 'DEFghi';

// 含まれていないと判定される
// mb_strposの戻り値が'0'の場合、誤判定するため
// mb_strposの判定は'==='で行うこと
if (mb_strpos($text2, $keyword2) == false) {
    echo $keyword2 . "は含まれていません" . "\n";
    echo mb_strpos($text2, $keyword2) . "文字目" . "\n";
} else {
    echo $keyword2 . "は含まれています" . "\n";
}

実行結果

DEFは含まれていません
0文字目

‘DEF’は含まれているはずなのに、含まれない判定になってしまいます。

Rubyの標準入出力

Paizaのスキルチェックしていて、Rubyのファイルの入出力についてある程度の知見が溜まってきたので、まとめます。

D,Cランクの問題で迷っていたら、試してみてください。

 

入力編

ファイルからの標準入力

Paizaのページ内にエディタがあるが、大半の人は自分のPCで開発すると思います。
私は、標準入力の使用頻度は高くないので、忘れがちです。
下記のコマンドで実行すると簡単です。

p gets # 1 2 3

インプットファイル

1 2 3

ターミナルにて実行

$ ruby Main.rb < input.txt
"1 2 3"
改行マークの除去

Paizaの問題には、標準入力に改行マークがあります。
除去するにはchompメソッドを使用します。

p gets
p gets.chomp

インプットファイル

1 2 3
1 2 3
$ ruby Main.rb < input.txt
"1 2 3\n"
"1 2 3"
標準入力を整数型にして、配列に格納する。

整数型にしないと、計算処理でエラーになります。

hoge = gets.split.map(&:to_i)
p hoge
p hoge[0] + 1

fuga = gets.split
p fuga
p fuga[0] + 1

インプットファイル

1 2 3
1 2 3

ターミナルにて実行

$ ruby Main.rb < input.txt 
[1, 2, 3]
2
["1", "2", "3"]
split.rb:7:in `+': no implicit conversion of Fixnum into String (TypeError)
        fromsplit.rb:7:in `<main>'

文字列型だとエラーになります。

データ部分の読み込み

Paizaの問題で標準入力で、よくあるのは最初の1行と、2行目以降だとデータの構造が違うことがあります。
自分が2行目以降の読み込みには、よく下記のコードを書きます。

# 1行目
p gets.split.map(&:to_i)

# 2行目以降読み込み
array_of_input = []
while s = gets
  array_of_input.push(s.split.map(&:to_i))
end
p array_of_input

インプットファイル

1 2 3
2 3 4 5 6
3 4 5 6 7

ターミナルにて実行

$ ruby Main.rb < input.txt 
[1, 2, 3]
[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

“while s = gets”で、標準入力の最後まで読み込むまで、1行を変数”s”に代入しています。

ヘッダー部分(最初の1行目)をインスタンス変数に格納して、その後の処理で使いやすくする。

ヘッダー部分は、仕様の根幹に関わる数値で、何回も参照する必要がでてくると思います。
classを作って、インスタンス変数に格納して、インスタンスの中で呼び出せる様にしましょう。

class Hoge
    def initialize(x, y, z)
        @x = x
        @y = y
        @z = z
    end
    
    def display
        p "x: " + @x.to_s
        p "y: " + @y.to_s
        p "z: " + @z.to_s
    end
end

x, y, z = gets.split.map(&:to_i)
hoge = Hoge.new(x, y, z)
hoge.display

インプットファイル

1 2 3
2 3 4 5 6
3 4 5 6 7

ターミナルにて実行

$ ruby Main.rb < input.txt 
"x: 1"
"y: 2"
"z: 3"

出力編

レシーバのクラスを表示する

型が不一致になることが原因で、エラーになることがあります。

a = 1
b = "1"

p a + b

上記の様な単純な例だったら、すぐに解決できますが、
デバッグしてると、クラスがわからないことがあります。
そこで、classメソッドを使用します。
classメソッドは、レシーバのクラスを返します。

hoge = "ruby"
p hoge.class #=> String

p 999999999999999.class #=> Bignum
p ARGV.class #=> Array
p self.class #=> Object
p Class.class #=> Class
p Kernel.class #=> Module
2次元配列を要素ごとに連結しつつ出力

たまに2次元配列の各要素を一行づつ連結して出力しなくてはならない場面があります。
その場合は下記のように記述すれば良いでしょう。

field = [[1,2],[3,4]]
# 連結
# 12
# 34
field.each { |f| puts f.join("")}
配列のnilを削除して計算を行う

配列にnilが混ざることも多いと思います。
nilがあって一番困るのは`inject`を使う時です。
そのような場合は、`compact`を使ってnilを削除しましょう。

array = [nil, 1, 2, 3, nil]
# nilを削除して計算
p array.compact.inject(&:+) # 6