以前にPHPではURLデコードまで自動的にやってくれるということを書いて、その後は処理するときの文字コードに変換など施してめちゃめちゃ食べやすい状態にしておくみたいなことをコードも交えてちらほら書いてきました。


が、少々小汚いコードだったことと、あの後にmb_convert_variables()関数という便利なのがあることを知って「SJIS-win」「CP51932」のような文字コード指定方法があることも知ったので今一度ここに書き直しておきます。


デコードその後の処理という意味でdecplus()という関数名にしました。
引数を渡さないと日本語EUCにするように書いたので以下では「SJIS-win」を渡してシフトJISにする処理で書いています。



[URLデコードその後]
<?php

decplus("SJIS-win");



function decplus($tojcode="CP51932")
{
    $fromjcode= "SJIS-win,UTF-8,CP51932,JIS";
    $fromtonl= array("\x0d\x0a"=>"\n", "\x0a"=>"\n", "\x0d"=>"\n");


    // binaryがあれば削って、改行コードを環境のものに統一して、前後ブランク文字があればトリミング
    function _decplus(&$array, $fromtonl){


        foreach ($array as $key=>&$value){


        if (is_array($value)) _decplus($value, $fromtonl);
        else $array[$key]= trim(strtr(preg_replace('/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\xff]/', "", $value), $fromtonl));
        }
    }


    mb_convert_variables($tojcode, $fromjcode, $_POST,$_REQUEST,$_GET,$_COOKIE);
    _decplus($_POST, $fromtonl);
    _decplus($_REQUEST, $fromtonl);
    _decplus($_GET, $fromtonl);
    _decplus($_COOKIE, $fromtonl);
}


?>



まずPHPスクリプトが受け取った時点での文字コードは未知であり私の場合はページ表示をシフトJISで行うので同じシフトJISで送信されてくる確率が高くなるため先頭に「SJIS-win」を書いています。
それと、シフトJISの半角カナのみだと日本語EUCと誤判定されるので必ず日本語EUCを表す「CP51932」より先に書くというのもあります。
幸いにもmb_convert_variables()関数は値を内部で連結させて、より高い精度での文字コード判定を行うようになっているようです。



decplus()関数内に_decplus()関数を書いていますがこれを呼び出して「バイナリコード」があれば削除して、改行コードを環境のものに統一させて、前後にブランク文字(空白)があれば取り除く処理を施しています。
フォームデータ値やクッキー値は配列でセットされている場合も考えられるので引数を参照渡しにして配列なら再帰処理にしています。
これと併せてforeachループでもリファレンスを使うことで引数に渡された配列そのものを変換するようにしています。これはPHP5からできるようになってるらしいです。


strtr()関数に渡す改行コード変換用配列は、このように一度に処理させることで先頭に書いた"\x0d\x0a"(CRLF)があればこれで優先的に処理するのでこの順番で書いています。



ちょっと過剰な処理になってしまったのでPOSTとGETに対応させてバイナリ除去・トリミングは不要なら以下のように書いてスッキリさせてもいいかと。



[URLデコードその後2]
<?php

decplus("SJIS-win");



function decplus($tojcode="CP51932")
{
    $fromjcode= "SJIS-win,UTF-8,CP51932,JIS";
    $fromtonl= array("\x0d\x0a"=>"\n", "\x0a"=>"\n", "\x0d"=>"\n");


    // 前後ブランク文字があればトリミング
    function _decplus(&$array, $fromtonl){


        foreach ($array as $key=>&$value){


        if (is_array($value)) _decplus($value, $fromtonl);
        else $array[$key]= strtr($value, $fromtonl);
        }
    }


    mb_convert_variables($tojcode, $fromjcode, $_POST,$_GET);
    _decplus($_POST, $fromtonl);
    _decplus($_GET, $fromtonl);
}


?>



昨日は傘を買いましたが、今日はヘッドホンを買いました。


左側が断線していて長いこと右しか聴こえていなかったのでずっと買いたいとは思っていたんですよね。
近所のいわゆる町の電気屋さんでヘッドホンを買うとやはり単独メーカーの出張所みたいなものなんで安くても5千円台とかになるんですよね。
実際にそこで某有名メーカーのを買ったことあるんですがすぐに断線してがっかりした覚えがあります。こういう町の電気屋さんにこそ安いヘッドホンとか置いてくれれば売れるのにね。



で、今回買ったのはキョーリツのHP-170というもの。
早速PCに取り付けてみてテレビジョンなぞを観て見る、いや音声を聴いてみる。。



いーかんじじゃないっすか イーカンジジャナイッスカ なんだかよさげじゃないっすか



右とか左とかからめちゃめちゃ聴こえるぅうううう!!



価格的にはこれまでに買った歴代の安物ヘッドホンとほとんど変わらない千円台半ば、


でもなんだか今度のはいい感じですぞよ なんというかその響きがいいね。
音に空間的広がりがあると言うか今まで聴こえなかった音まで聴こえる感じ


これには満足。でもこれもいつかは壊れるだろう。そのときはまたこれと同じ型のやつ買うかも


ボギーボビーのように朽ち果てるとも・・・



と、デジカメで撮ろうとしたらバッテリー切れだったし。3時間ぐらいかけて充電して投稿




[キョーリツ HP-170]
そろそろホンキ出す-ヘッドホン


光量が足りないのかあまりキレイに撮れない



コンパイルの前段階として「プリプロセッサ」と呼ばれる内部プログラムが、プリプロセス(前処理)を行いコンパイルにバトンタッチする。



プリプロセス文は一行単位。(行末に「;」セミコロンとかは不要)
複数行に渡る場合は末尾\を書くことで次行につなけることができる。
行頭はインデント(字下げ)してもよい。


つまり

#include "foo.h"
と書いても
    #include \
"foo.h"
と書いても同じ挙動になる




■マクロ置換


#define 記号定数 置き換え文字


プログラム中に直接値を埋め込むことは「マジックナンバー」と言われ嫌われます。
マジシャンじゃないと意味が分からない値ということで、私たち普通の人間がソースコードを読むのが難解になってしまいます。


ということで値は埋め込まずにファイル頭にくくり出してマクロ置換できるようにすれば読みやすくなります。当然読んで意味の分かる記号定数にしないとあまり効果ないことですが・・



[マクロ置換例]
#include <stdio.h>
#define FIRST_NAME "山田"
#define SECOND_NAME "太郎"

int main(void)
{
    printf("%s\n", "名前は" FIRST_NAME SECOND_NAME);


    return 0;
}



これは「名前は山田太郎[改行]」という表示になります。
"1" "2" "3"のような文字列リテラルの連続はコンパイル時に連結されて末尾に文字列終端がほどこされて一つの文字列扱いになるのでこれがprintf関数に渡って末尾に改行が付く文字列として表示するようになります。




■ファイル取り込み


#include <foo.h>
#include "bar.h"


<foo.h>と"bar.h"の違いは、前者はコンパイラが特定のディレクトリからfoo.hファイルを探索するのに対して、後者はソースファイルのある場所を先に探索して、なければ前者と同じ動作になる。
これはコンパイル時にコマンドラインオプション「-I」を使って、ヘッダファイルの探索パスを「-I.」のように指定するのと似ている。


#defineが文字列置換なら、#includeはファイル内容置換という感じですね。



[ファイル取り込み例]
#include <stdio.h>

#include "main.txt"
/* int main(void) */
{
    printf("動くかな?\n");


    return 0;
}



[取り込まれるmain.txt内容]

int main(void)



あり得ないようなひどい例になってしまいましたが、これはプリプロセスにおいてmain関数が成立するように置き換えられます。




■条件付き


#ifdef 記号定数
    「プリプロセス文」または「Cコード」
#elif 記号定数
    「プリプロセス文」または「Cコード」
#else
    「プリプロセス文」または「Cコード」
#endif


他のプリプロセス文と組み合わせたり、Cのソースコードを条件付きで有効無効にしたりして結果的に条件付コンパイルを実現する。


条件によって#defineで置換文字を変えたり、#includeで取り込むファイルを変えたりデバッグ値を表示させたり用途はかなり広い


#ifdef 記号定数は#if defined(記号定数)と同じ
#ifndef 記号定数は#if !defined(記号定数)と同じ



#if条件に使える定数は、少なくとも前処理段階で定数でないといけないのでsizeof演算子やenum定数は使えない。

#if 記号定数 == 記号定数
#if (記号定数 == 1) || (記号定数 == 2)
#if 記号定数 < 100
#if 記号定数 >= 0

のような演算が使える



よくあるヘッダファイルの二重取り込み防止
#ifndef FOO_H
#define FOO_H

/* foo.h内容をここに書く */


#endif




■未定義化


#undef 記号定数


記号定数を無効化できる。