ヒアドキュメントでエラーが出る〜Can't find string terminator〜

ヒアドキュメントを使っているときに、以下のエラーが出ていて、うんうんうなってしまった。

[Tue Oct 26 16:45:40 2010] [error] [client ::1] Can't find string terminator "ERR_HTML" anywhere before EOF

ま、原因は以下を守ってなかったから。

■ヒアドキュメントを使用するときに気をつけること
・ヒアドキュメントの終了を示す行は、ヒアドキュメントとして指定した文字列と改行コードのみを書く
→行頭にタブやスペースを入れるのもダメ。

ヒアドキュメントのお約束をすっかり忘れてました。。。

エクセルマクロ

とりあえずアップ。

Private sheet_name As String
Private i As Integer
Sub push()
Call get_sheet_name
'工数を書き込むシート名が今日の日付でない、かつ「退社」が押されていたら今日分を入力するシートを作り、作ったシートにデータを蓄積する
If sheet_name <> Date$ And Worksheets(sheet_name).Cells(Rows.Count, 2).End(xlUp).Value = "退社" Then
    Call create_new_sheet
    Call get_sheet_name
End If
Call get_final_row_number
Call reflect_to_row
'入力項目に不備がある時はなにも入力せずに終了
If Not IsEmpty(Worksheets(sheet_name).Range("B" & i).Value) Or Not IsEmpty(Worksheets(sheet_name).Range("C" & i).Value) Then
    Call get_time
End If
Worksheets("計測用FMT").Activate
End Sub
Sub get_sheet_name()
If ActiveWorkbook.Sheets.Count = 2 Then
    Call create_new_sheet
ElseIf ActiveWorkbook.Sheets.Count < 2 Then
    MsgBox "ファイルが壊れてるみたいだから、新しいファイルを用意してね。"
End If
sheet_name = Worksheets(3).Name
End Sub
Sub create_new_sheet()
'案件一覧シートの右側にデータ記録用の新しいシートを作る
Dim newsheet As Worksheet
Set newsheet = Worksheets.Add(after:=Worksheets("案件一覧"))
With newsheet
    .Name = Date$
End With
End Sub
Sub get_final_row_number()
'終端セルの行数を取得する
If IsEmpty(Worksheets(sheet_name).Range("A1").Value) Then
    i = 1
Else
    '終端セルの行数を取得したいシートをアクティブにしないと1004エラーが出るよ
    Worksheets(sheet_name).Activate
    '下記はオーバーフローになるからだめ
    'i = Worksheets(sheet_name).Range("A1").End(xlDown).Row
    Worksheets(sheet_name).Range("A" & Rows.Count).End(xlUp).Select
    i = ActiveCell.Row
    i = i + 1
End If
End Sub
Sub get_time()
'システム時刻を取得して入力
Worksheets(sheet_name).Range("A" & i).Value = Time
End Sub
Sub reflect_to_row()
'計測用FMT上でエラーを出すためにシートをアクティブにする
Worksheets("計測用FMT").Activate
'必須項目に記入漏れがないか確認
If IsEmpty(Worksheets("計測用FMT").Range("C3").Value) And IsEmpty(Worksheets("計測用FMT").Range("D3").Value) Then
    MsgBox "業務内容を入れてね"
ElseIf Not IsEmpty(Worksheets("計測用FMT").Range("C3").Value) And Not IsEmpty(Worksheets("計測用FMT").Range("D3").Value) Then
    MsgBox "直接と間接、両方入れちゃだめだよ"
ElseIf Not IsEmpty(Worksheets("計測用FMT").Range("D3").Value) And IsEmpty(Worksheets("計測用FMT").Range("E3").Value) Then
    MsgBox "案件名を入れてね"
Else
   '業務内容、案件名、詳細作業を行に反映
    Worksheets(sheet_name).Range("B" & i).Value = Worksheets("計測用FMT").Range("C3").Value
    Worksheets(sheet_name).Range("C" & i).Value = Worksheets("計測用FMT").Range("D3").Value
    Worksheets(sheet_name).Range("D" & i).Value = Worksheets("計測用FMT").Range("E3").Value
    Worksheets(sheet_name).Range("E" & i).Value = Worksheets("計測用FMT").Range("F3").Value
    
    'フォームの値を初期化
    Worksheets("計測用FMT").Range("C3:F3").ClearContents
End If
End Sub

サーバー情報を隠す設定をする〜apacheのhttpd.conf〜

■エラーメッセージを出すときにサーバー情報を隠す

#ServerSignature On
ServerSignature Off

サーバが生成するドキュメント (エラーメッセージ、mod_proxy における FTPディレクトリリスト、 mod_info の出力、等々) の最下行に付与するフッタの設定を行ないます。

出典:apacheマニュアル
http://httpd.apache.org/docs/2.1/ja/mod/core.html#serversignature


■クライアントへの戻り値からもサーバー情報を隠す
ServerSignatureの下辺りに書けばオッケーです。

ServerTokens ProductOnly

このディレクティブは、クライアントに送り返す Server 応答ヘッダ内に、サーバの一般的な OS 種別や、 コンパイルされて組み込まれているモジュールの情報を 含めるかどうかを指定します。

出典:apacheのマニュアル
http://httpd.apache.org/docs/2.1/ja/mod/core.html#servertokens

「Premature end of script headers」のエラーが出たときの解消法

MVCモデルの勉強として、先輩がちっちゃなMVCモデルのプログラムを作ってくれました。それをベースにいろいろ機能追加をはかっていたのですが、デバック方法がわからない!というか、ブラウザにデバック内容を表示させたい。おまけにapacheのログでこんなエラー↓が出る(涙)!

[Wed Oct 06 20:26:57 2010] [error] [client 192.168.20.1] Premature end of script headers

躍起になっていろいろ調べて聞いて、習得しました。

■方法/以下の一行をブラウザに表示させたい内容の前に入れる。
print "\n\n";

こんな感じ↓です。

print "\n\n";  #「ヘッダー終わり」の印
#useはなにもプログラムの上に書かなくては動かない、というわけではありません
use Data::Dumper;
#$aの内容を見たい→ブラウザの更新ボタンを押すとブラウザに表示されます
print Dumper $a;

なんで「\n\n」をprintしないといけないのかというと、ブラウザとWebサーバーのやり取りに関係しています。

■ブラウザとWebサーバーのやり取り
(1)ブラウザからプログラムにリクエストが来る
(2)リクエストをWebサーバー(apache)が受け取ってプログラムが動く
(3)プログラムが処理結果をapacheに渡す
(4)apacheがブラウザに処理結果を返す
(5)ブラウザが返ってきた結果を表示する
↓↓
(5)のときに、「ヘッダーの終わり」が無いとエラー(Premature end of script headers)が出るんです。
「ヘッダーの終わり」がないと、表示させようとしている内容もヘッダーの一部とみなされ、「ヘッダーが全部来てなよ!」、と叱られるわけです。

よく、「Premature end of script headers」でWeb検索かけると、「Content-Type」が無いからだ、と書かれていますが、Content-Typeがなくても「\n\n」があれば表示できるそうです。実際できました。んじゃ、Content-Typeって一体なによ、なにしてるのよ、っていうと、以下。

■Content-Typeの役割
返す値(ファイル)の種類を受け手側にお知らせしていて、受け手側に、何のアプリケーションで開けば良いのか、どんな形式の情報なのか、を伝えている。

今回の場合は、別になくてもいいわけです。先輩も、重要なのはContent-Typeより「ヘッダーの終わり」。ここまで書いてなんですが、ヘッダーの終わりは、改行2個です。

ref関数〜変数の型を確認したい〜

ref関数は、引数によって真か偽かを返す関数です。

■引数がリファレンスの場合
「真」つまり、リファレンスが参照する型を返します。
なお、返す型は以下です。

・SCALAR   スカラー
・ARRAY    配列
・HASH    ハッシュ
・REF     リファレンス
・CODE    サブルーチン
・パッケージ名 blessされているもの
・GLOB    型グロブ

■引数がリファレンスでない場合
「偽」を返します。

こんな感じで使います。

■処理内容
#$kをハッシュのキーに、$vをハッシュの値(value)として%paramsに追加していきたい。
#$kがすでに存在しているキーの場合、値(value)を配列のリファレンスにして$vを入れる
#つまり、キーの重複によるvalueの上書きはしない

■スクリプト
#$kがすでにハッシュのキーとして存在していなければ普通にキー、valueとして追加
if (!exists($params{$k})){
    $params{$k} = $v;

#$kのvalueが、配列のリファレンスになっていなければ配列のリファレンスにして$vを追加
}elsif(!ref $params{$k}){
    $params{$k} = [$params{$k}, $v];
                                                                            
#$kのvalueがすでに配列のリファレンスになっている場合、そのまま$vを追加
}else{
    push @{$params{$k}}, $v;
}

ref関数を使用してはまったら、まず、ref関数に渡している引数がリファレンスかどうかをよく確認してみてください。

私は、リファレンスでないスカラー変数をrefの引数に与え、どーしてSCALARが返らないのだっ!、とはまりにはまりました。脳みそが煮えたので、先輩に聞くとあっさり。。。はまって自分で抜け出せないのは、ものすごくくやしい。

excelで挿入ペースト(挿入貼付け)をしたい!

挿入ペーストの方法をころっと忘れてしまったので、めも。上書きペーストしたくないときにどうぞ。

ペーストしたい内容をコピー
Ctrl+C
↓
挿入貼付け
Ctrl+Shift+[+]
コピー範囲を解除
ESC

ちなみに、セル内改行はこれ↓。

Alt + Enter

あれだけ学生の頃つかったショートカットなのに、使用頻度がほぼ0になったとたん記憶から抹消されていた。。。私の記憶力って、ホント弱い。