[PHP]テキストに自動で段落分け<p>、改行<br />タグをつける(文字列のHTML化)

通常のテキストを自動整形して HTML 文書として出力するには、preg_split() で段落分けをし、
nl2br() で改行タグを付ける方法が簡単です。

2つ以上改行が連続した場合を段落分けと判断し、その他を改行として処理します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$str = <<<EOD
段落1
二行目
 
段落2
二行目
EOD;
 
echo html_paragraph($str);
 
function html_paragraph($str, $xhtml=true){
    $arr = preg_split("/\R\R+/", $str, -1, PREG_SPLIT_NO_EMPTY);
    $result = "";
    foreach($arr as $value){
        $value = htmlspecialchars($value, ENT_QUOTES);
        $result .= '<p>' . nl2br($value, $xhtml) . "</p>\n";
    }
    return $result;
}

[出力結果]

1
2
3
4
<p>段落1<br />
二行目</p>
<p>段落2<br />
二行目</p>

「<br /><br />」のように改行タグを連続して使用するよりは
ソースとして綺麗になるのでブログの記事内容を出力する時などに使えると思います。

[PHP]多次元配列の次元の深さ(階層)を調べる

多次元配列の内、最も深い階層の次元数をカウントする関数を作ってみました。
「123」などの配列でないものは 0 を返し、「array(1,2,3)」等の場合は 1 を返します。
「$arr[0][0][0][0][0] = 123」だと 5 になります。
「array(1, array(2), 3)」のように混在している場合は最も深いものを返すので 2 になります。

1
2
3
4
5
6
7
8
9
10
11
12
function array_depth($arr, $blank=false, $depth=0){
    if( !is_array($arr)){
        return $depth;
    } else {
        $depth++;
        $tmp = ($blank) ? array($depth) : array(0);
        foreach($arr as $value){
            $tmp[] = array_depth($value, $blank, $depth);
        }
        return max($tmp);
    }
}

「array( array() )」など、配列の内容が空の場合、デフォルトでは 0 になりますが、
$blank を true にすることで 2 としてカウントすることもできます。

[PHP]PDO bindParamで同じ変数名を使うと内容も同じになる

プレースホルダに bindParam() を使って値をセットする時、
同じ変数名を使うと参照渡しが行われてしまい、最後にセットした値が
全てのプレースホルダにセットされてしまいます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$host = 'localhost';
$name = 'test';
$user = 'user';
$pass = 'password';
 
try {
    $dsn = "mysql:host={$host};dbname={$name};charset=utf-8";
    $db = new PDO($dsn, $user, $pass);
} catch (PDOExceprion $e){
    echo $e->getMessage();
}
 
$sql = "SELECT * FROM sample WHERE (name = ? OR name = ?)";
 
$stmt = $db->prepare($sql);
 
$value = "foo";
$stmt->bindParam(1, $value);
 
$value = "bar";
$stmt->bindParam(2, $value);
 
$stmt->execute();

上の例では、
「SELECT * FROM sample WHERE (name = ? OR name = ?)」
という SQL 文の疑問符部分に対してそれぞれ「foo」と「bar」をバインドしています。

「name = ‘foo’ OR name = ‘bar’」となるつもりが、実際の結果は
「name = ‘bar’ OR name = ‘bar’」となってしまいました。

どちらも value と言う変数名を使っているため、後から代入した値によって
他の値が上書きされています。
$value1, $value2 のように名前を分ければこれは発生しません。
あるいは一度使った $value を unset() しておけば同じ名前であっても大丈夫です。

1
2
3
4
5
6
7
$value = "foo";
$stmt->bindParam(1, $value);
 
unset($value);
 
$value = "bar";
$stmt->bindParam(2, $value);

execute() を行うまでは $value に代入した時点で上書きが行われるので、
bindParam() を使ったかどうかは実際には関係ありません。
次のようにすると全てのパラメータは「hello」に上書きされます。

1
2
3
4
5
6
7
$value = "foo";
$stmt->bindParam(1, $value);
 
$value = "bar";
$stmt->bindParam(2, $value);
 
$value = "hello";

【結果】

SELECT * FROM sample WHERE (name = 'hello' OR name = 'hello')

ループ内で使う場合は、参照渡し「&$value」を使って bindParam() を行います。
後から問題を起こさないように使った変数は unset() で片付けておきます。

1
2
3
4
5
$i=1;foreach($arr as &$value){
  $stmt->bindParam($i, $value);
  $i++;
}
unset($value);

参照渡しをしない bindValue() を使えばこの問題が発生しないので、bindParam にこだわりがなければ
for や foreach などのループ内では bindValue() を使ったほうが無駄な混乱が起こりにくくなると思います。